Parser.php
Current file: /Volumes/DataHD/Users/philipp/Projects/github/pfrischmuth/OntoWiki.git/libraries/Erfurt/library/Erfurt/Sparql/Parser.php
Legend: executed not executed dead code

  Coverage
  Classes Functions / Methods Lines
Total
0.00% 0 / 1
42.86% 15 / 35 CRAP
83.63% 894 / 1069
Erfurt_Sparql_Parser
0.00% 0 / 1
42.86% 15 / 35 883.36
83.63% 894 / 1069
 tokenize($queryString)
0.00% 0 / 1 48.18
89.90% 89 / 99
 uncomment($queryString)
100.00% 1 / 1 1
100.00% 2 / 2
 balanceTree(&$tree)
100.00% 1 / 1 7
100.00% 14 / 14
 fixNegationInFuncName(&$tree)
0.00% 0 / 1 4.02
88.89% 8 / 9
 parse($queryString = false)
0.00% 0 / 1 3.33
66.67% 8 / 12
 _bNodeCheck($token)
100.00% 1 / 1 2
100.00% 3 / 3
 _checkDtypeLang(&$node, $nSubstrLength = 1)
100.00% 1 / 1 5
100.00% 30 / 30
 _dissallowBlankNodes()
100.00% 1 / 1 2
100.00% 4 / 4
 _dtypeCheck(&$node)
0.00% 0 / 1 5.07
85.71% 24 / 28
 _fastForward()
100.00% 1 / 1 2
100.00% 5 / 5
 _iriCheck($token)
100.00% 1 / 1 2
100.00% 4 / 4
 _literalCheck($token)
100.00% 1 / 1 3
100.00% 6 / 6
 _parseAsk($form)
100.00% 1 / 1 3
100.00% 6 / 6
 _parseBase()
0.00% 0 / 1 2.09
71.43% 5 / 7
 _parseCollection(&$trp)
0.00% 0 / 1 10.02
94.34% 50 / 53
 _parseConstraint(&$pattern, $outer)
100.00% 1 / 1 2
100.00% 9 / 9
 _parseConstraintTree($nLevel = 0, $bParameter = false)
0.00% 0 / 1 87.32
86.55% 148 / 171
 _parseConstruct()
0.00% 0 / 1 4.70
64.71% 11 / 17
 _parseDescribe()
100.00% 1 / 1 7
100.00% 15 / 15
 _parseFrom()
0.00% 0 / 1 14.91
52.38% 11 / 21
 _parseGraph()
0.00% 0 / 1 8.32
70.00% 14 / 20
 _parseGraphPattern($optional = false, $union = false, $graph = false, $constr = false, $external = false, $subpattern = false)
0.00% 0 / 1 18.39
89.39% 59 / 66
 _parseLiteral(&$node, $sep)
100.00% 1 / 1 5
100.00% 15 / 15
 _parseModifier()
0.00% 0 / 1 6.02
92.00% 23 / 25
 _parseNode($node = false)
0.00% 0 / 1 33.14
73.24% 52 / 71
 _parseOrderCondition()
0.00% 0 / 1 35.14
74.68% 59 / 79
 _parsePrefix()
0.00% 0 / 1 2.03
80.00% 8 / 10
 _parseQuery()
0.00% 0 / 1 13
95.00% 38 / 40
 _parseSelect()
0.00% 0 / 1 34.52
60.71% 34 / 56
 _parseTriplePattern(&$pattern)
0.00% 0 / 1 33.49
82.52% 118 / 143
 _parseWhere()
0.00% 0 / 1 2.21
62.50% 5 / 8
 _prepare()
100.00% 1 / 1 1
100.00% 5 / 5
 _qnameCheck($token)
0.00% 0 / 1 5.02
60.00% 6 / 10
 _rewind()
100.00% 1 / 1 1
100.00% 2 / 2
 _varCheck($token)
100.00% 1 / 1 4
100.00% 4 / 4


       1                 : <?php                                                                                                                                                          
       2                 : /**                                                                                                                                                            
       3                 :  * This file is part of the {@link http://aksw.org/Projects/Erfurt Erfurt} project.                                                                            
       4                 :  *                                                                                                                                                             
       5                 :  * @copyright Copyright (c) 2012, {@link http://aksw.org AKSW}                                                                                                 
       6                 :  * @license http://opensource.org/licenses/gpl-license.php GNU General Public License (GPL)                                                                    
       7                 :  */                                                                                                                                                            
       8                 :                                                                                                                                                                
       9                 : /**                                                                                                                                                            
      10                 :  * Parses a SPARQL Query string and returns a Erfurt_Sparql_Query Object.                                                                                      
      11                 :  *                                                                                                                                                             
      12                 :  * This class was originally adopted from rdfapi-php (@link http://sourceforge.net/projects/rdfapi-php/).                                                      
      13                 :  * It was modified and extended in order to fit into Erfurt.                                                                                                   
      14                 :  *                                                                                                                                                             
      15                 :  * @package Erfurt_Sparql                                                                                                                                      
      16                 :  * @author Tobias Gauss <tobias.gauss@web.de>                                                                                                                  
      17                 :  * @author Christian Weiske <cweiske@cweiske.de>                                                                                                               
      18                 :  * @author Philipp Frischmuth <pfrischmuth@googlemail.com>                                                                                                     
      19                 :  * @license http://www.gnu.org/licenses/lgpl.html LGPL                                                                                                         
      20                 :  */                                                                                                                                                            
      21                 : class Erfurt_Sparql_Parser                                                                                                                                     
      22                 : {                                                                                                                                                              
      23                 :     // ------------------------------------------------------------------------                                                                                
      24                 :     // --- Protected static properties ----------------------------------------                                                                                
      25                 :     // ------------------------------------------------------------------------                                                                                
      26                 :                                                                                                                                                                
      27                 :     /**                                                                                                                                                        
      28                 :      * Which order operators are to be treated (11.3 Operator Mapping).                                                                                        
      29                 :      *                                                                                                                                                         
      30                 :      * @var array                                                                                                                                              
      31                 :      */                                                                                                                                                        
      32                 :     protected static $_operatorPrecedence = array(                                                                                                             
      33                 :         '||' => 0,                                                                                                                                             
      34                 :         '&&' => 1,                                                                                                                                             
      35                 :         '='  => 2,                                                                                                                                             
      36                 :         '!=' => 3,                                                                                                                                             
      37                 :         '<'  => 4,                                                                                                                                             
      38                 :         '>'  => 5,                                                                                                                                             
      39                 :         '<=' => 6,                                                                                                                                             
      40                 :         '>=' => 7,                                                                                                                                             
      41                 :         '*'  => 0,                                                                                                                                             
      42                 :         '/'  => 0,                                                                                                                                             
      43                 :         '+'  => 0,                                                                                                                                             
      44                 :         '-'  => 0,                                                                                                                                             
      45                 :     );                                                                                                                                                         
      46                 :                                                                                                                                                                
      47                 :     /**                                                                                                                                                        
      48                 :      * Operators introduced by sparql.                                                                                                                         
      49                 :      *                                                                                                                                                         
      50                 :      * @var array                                                                                                                                              
      51                 :      */                                                                                                                                                        
      52                 :     protected static $_sops = array('regex', 'bound', 'isuri', 'isblank',                                                                                      
      53                 :         'isliteral', 'str', 'lang', 'datatype', 'langmatches'                                                                                                  
      54                 :     );                                                                                                                                                         
      55                 :                                                                                                                                                                
      56                 :     // ------------------------------------------------------------------------                                                                                
      57                 :     // --- Protected properties -----------------------------------------------                                                                                
      58                 :     // ------------------------------------------------------------------------                                                                                
      59                 :                                                                                                                                                                
      60                 :     /**                                                                                                                                                        
      61                 :      * The query object.                                                                                                                                       
      62                 :      *                                                                                                                                                         
      63                 :      * @var Erfurt_Sparql_Query                                                                                                                                
      64                 :      */                                                                                                                                                        
      65                 :     protected $_query;                                                                                                                                         
      66                 :                                                                                                                                                                
      67                 :     /**                                                                                                                                                        
      68                 :      * Last parsed graphPattern.                                                                                                                               
      69                 :      *                                                                                                                                                         
      70                 :      * @var int                                                                                                                                                
      71                 :      */                                                                                                                                                        
      72                 :     protected $_tmp;                                                                                                                                           
      73                 :                                                                                                                                                                
      74                 :     /**                                                                                                                                                        
      75                 :      * The tokenized query.                                                                                                                                    
      76                 :      *                                                                                                                                                         
      77                 :      * @var array                                                                                                                                              
      78                 :      */                                                                                                                                                        
      79                 :     protected $_tokens = array();                                                                                                                              
      80                 :                                                                                                                                                                
      81                 :     /**                                                                                                                                                        
      82                 :      * Contains blank node ids as key and an boolean value as value.                                                                                           
      83                 :      * This array is used in order to invalidate used blank node ids in some                                                                                   
      84                 :      * cases.                                                                                                                                                  
      85                 :      */                                                                                                                                                        
      86                 :     protected $_usedBlankNodes = array();                                                                                                                      
      87                 :                                                                                                                                                                
      88                 :     // ------------------------------------------------------------------------                                                                                
      89                 :     // --- Public static methods ----------------------------------------------                                                                                
      90                 :     // ------------------------------------------------------------------------                                                                                
      91                 :                                                                                                                                                                
      92                 :     /**                                                                                                                                                        
      93                 :      * Tokenizes the query string into $tokens.                                                                                                                
      94                 :      * The query may not contain any comments.                                                                                                                 
      95                 :      *                                                                                                                                                         
      96                 :      * @param  string $queryString Query to split into tokens                                                                                                  
      97                 :      * @return array Tokens                                                                                                                                    
      98                 :      */                                                                                                                                                        
      99                 :     public static function tokenize($queryString)                                                                                                              
     100                 :     {                                                                                                                                                          
     101             335 :         $inTelUri = false;                                                                                                                                     
     102             335 :         $inUri = false;                                                                                                                                        
     103                 :                                                                                                                                                                
     104             335 :         $queryString = trim($queryString);                                                                                                                     
     105                 :                                                                                                                                                                
     106             335 :         $removeableSpecialChars = array(' ', "\t", "\r", "\n");                                                                                                
     107             335 :         $specialChars           = array(',', '\\', '(', ')', '{', '}', '"', "'", ';', '[', ']');                                                               
     108                 :                                                                                                                                                                
     109             335 :         $len    = strlen($queryString);                                                                                                                        
     110             335 :         $tokens = array();                                                                                                                                     
     111             335 :         $n      = 0;                                                                                                                                           
     112                 :                                                                                                                                                                
     113             335 :         $inLiteral   = false;                                                                                                                                  
     114             335 :         $longLiteral = false;                                                                                                                                  
     115                 :                                                                                                                                                                
     116             335 :         for ($i=0; $i<$len; ++$i) {                                                                                                                            
     117             335 :             if (in_array($queryString[$i], $removeableSpecialChars) && !$inLiteral && !$inTelUri) {                                                            
     118             335 :                 if (isset($tokens[$n]) && $tokens[$n] !== '') {                                                                                                
     119             335 :                     if ((strlen($tokens[$n]) >= 2)) {                                                                                                          
     120             335 :                         if (($tokens[$n][strlen($tokens[$n])-1] === '.') &&                                                                                    
     121             335 :                                 !is_numeric(substr($tokens[$n], 0, strlen($tokens[$n])-1))) {                                                                  
     122                 :                                                                                                                                                                
     123              16 :                             $tokens[$n] = substr($tokens[$n], 0, strlen($tokens[$n])-1);                                                                       
     124              16 :                             $tokens[++$n] = '.';                                                                                                               
     125             335 :                         } else if (($tokens[$n][0] === '.')) {                                                                                                 
     126               0 :                             $dummy = substr($tokens[$n], 1);                                                                                                   
     127               0 :                             $tokens[$n] = '.';                                                                                                                 
     128               0 :                             $tokens[++$n] = $dummy;                                                                                                            
     129               0 :                         }                                                                                                                                      
     130             335 :                     }                                                                                                                                          
     131                 :                                                                                                                                                                
     132             335 :                     $n++;                                                                                                                                      
     133             335 :                 }                                                                                                                                              
     134                 :                                                                                                                                                                
     135             335 :                 continue;                                                                                                                                      
     136             335 :             } else if (in_array($queryString[$i], $specialChars) && !$inTelUri && !$inUri) {                                                                   
     137             334 :                 if ($queryString[$i] === '"' || $queryString[$i] === "'") {                                                                                    
     138              78 :                     $foundChar = $queryString[$i];                                                                                                             
     139              78 :                     if (!$inLiteral) {                                                                                                                         
     140                 :                         // Check for long literal                                                                                                              
     141              78 :                         if (($queryString[($i+1)] === $foundChar) && ($queryString[($i+2)] === $foundChar)) {                                                  
     142              12 :                             $longLiteral = true;                                                                                                               
     143              12 :                         }                                                                                                                                      
     144                 :                                                                                                                                                                
     145              78 :                         $inLiteral = true;                                                                                                                     
     146              78 :                     } else {                                                                                                                                   
     147                 :                         // We are inside a literal... Check whether this is the end of the literal.                                                            
     148              78 :                         if ($longLiteral) {                                                                                                                    
     149              12 :                             if (($queryString[($i+1)] === $foundChar) && ($queryString[($i+2)] === $foundChar)) {                                              
     150              12 :                                 $inLiteral = false;                                                                                                            
     151              12 :                                 $longLiteral = false;                                                                                                          
     152              12 :                             }                                                                                                                                  
     153              12 :                         } else {                                                                                                                               
     154              66 :                             $inLiteral = false;                                                                                                                
     155                 :                         }                                                                                                                                      
     156                 :                     }                                                                                                                                          
     157              78 :                 }                                                                                                                                              
     158                 :                                                                                                                                                                
     159             334 :                 if (isset($tokens[$n]) && ($tokens[$n] !== '')) {                                                                                              
     160                 :                     // Check whether trailing char is a dot.                                                                                                   
     161             157 :                     if ((strlen($tokens[$n]) >= 2)) {                                                                                                          
     162             146 :                         if (($tokens[$n][strlen($tokens[$n])-1] === '.') &&                                                                                    
     163             146 :                                 !is_numeric(substr($tokens[$n], 0, strlen($tokens[$n])-1))) {                                                                  
     164                 :                                                                                                                                                                
     165               0 :                             $tokens[$n] = substr($tokens[$n], 0, strlen($tokens[$n])-1);                                                                       
     166               0 :                             $tokens[++$n] = '.';                                                                                                               
     167             146 :                         } else if (($tokens[$n][0] === '.')) {                                                                                                 
     168               1 :                             $dummy = substr($tokens[$n], 1);                                                                                                   
     169               1 :                             $tokens[$n] = '.';                                                                                                                 
     170               1 :                             $tokens[++$n] = $dummy;                                                                                                            
     171               1 :                         }                                                                                                                                      
     172             146 :                     }                                                                                                                                          
     173                 :                                                                                                                                                                
     174             157 :                     $tokens[++$n] = '';                                                                                                                        
     175             157 :                 }                                                                                                                                              
     176                 :                                                                                                                                                                
     177                 :                 // In case we have a \ in the string we add the following char to the current token.                                                           
     178                 :                 // In that case it doesn't matter what type of char the following one is!                                                                      
     179             334 :                 if ($queryString[$i] === '\\') {                                                                                                               
     180                 :                     // Escaped chars do not need a new token.                                                                                                  
     181              16 :                     $n--;                                                                                                                                      
     182                 :                                                                                                                                                                
     183              16 :                     $tokens[$n] .= $queryString[$i] .  $queryString[++$i];                                                                                     
     184                 :                                                                                                                                                                
     185                 :                     // In case we have added \u we will also add the next 4 digits.                                                                            
     186              16 :                     if ($queryString[$i] === 'u') {                                                                                                            
     187               2 :                         $tokens[$n] .= $queryString[++$i] . $queryString[++$i]. $queryString[++$i]. $queryString[++$i];                                        
     188               2 :                     }                                                                                                                                          
     189                 :                                                                                                                                                                
     190              16 :                     $n++;                                                                                                                                      
     191              16 :                 }                                                                                                                                              
     192                 :                 // Sparql supports literals that are written as """...""" in order to support quotation inside                                                 
     193                 :                 // the literal.                                                                                                                                
     194             334 :                 else if (($queryString[$i] === '"') && ($i<($len-2)) && ($queryString[($i+1)] === '"') &&                                                      
     195             334 :                         ($queryString[($i+2)] === '"')) {                                                                                                      
     196               7 :                     $tokens[$n++] = $queryString[$i] .  $queryString[++$i] . $queryString[++$i];                                                               
     197               7 :                 }                                                                                                                                              
     198                 :                 // Sparql supports literals that are written as '''...''' in order to support quotation inside                                                 
     199                 :                 // the literal.                                                                                                                                
     200             334 :                 else if (($queryString[$i] === "'") && ($i<($len-2)) && ($queryString[($i+1)] === "'") &&                                                      
     201             334 :                         ($queryString[($i+2)] === "'")) {                                                                                                      
     202               6 :                     $tokens[$n++] = $queryString[$i] .  $queryString[++$i] . $queryString[++$i];                                                               
     203               6 :                 } else {                                                                                                                                       
     204             334 :                     $tokens[$n++] = $queryString[$i];                                                                                                          
     205                 :                 }                                                                                                                                              
     206             334 :             } else {                                                                                                                                           
     207                 :                 // Special care for tel URIs                                                                                                                   
     208             335 :                 if (substr($queryString, $i, 5) === '<tel:') {                                                                                                 
     209               0 :                     $inTelUri = true;                                                                                                                          
     210               0 :                 }                                                                                                                                              
     211             335 :                 if ($inTelUri && $queryString[$i] === '>') {                                                                                                   
     212               0 :                     $inTelUri = false;                                                                                                                         
     213               0 :                 }                                                                                                                                              
     214                 :                                                                                                                                                                
     215                 :                                                                                                                                                                
     216             335 :                 if (!isset($tokens[$n])) {                                                                                                                     
     217             335 :                     $tokens[$n] = '';                                                                                                                          
     218             335 :                 }                                                                                                                                              
     219                 :                                                                                                                                                                
     220                 :                 // Iris written as <><><> can be written without whitespace, so we need to test for this.                                                      
     221                 :                 // If yes, we need to start a new token.                                                                                                       
     222             335 :                 if ((substr($tokens[$n], 0, 1) === '<') && ($queryString[$i] === '>')) {                                                                       
     223             262 :                     $tokens[$n++] .= $queryString[$i];                                                                                                         
     224             262 :                     $inUri = false;                                                                                                                            
     225             262 :                     continue;                                                                                                                                  
     226             335 :                 } else if ($queryString[$i] === '<') {                                                                                                         
     227             262 :                     $inUri = true;                                                                                                                             
     228             262 :                     if ($tokens[$n] === '') {                                                                                                                  
     229             262 :                         $tokens[$n] = '<';                                                                                                                     
     230             262 :                         continue;                                                                                                                              
     231                 :                     } else {                                                                                                                                   
     232               1 :                         $tokens[++$n] = '<';                                                                                                                   
     233               1 :                         continue;                                                                                                                              
     234                 :                     }                                                                                                                                          
     235                 :                                                                                                                                                                
     236                 :                 }                                                                                                                                              
     237                 :                                                                                                                                                                
     238             335 :                 $tokens[$n] .= $queryString{$i};                                                                                                               
     239                 :             }                                                                                                                                                  
     240             335 :         }                                                                                                                                                      
     241                 :                                                                                                                                                                
     242             335 :         return $tokens;                                                                                                                                        
     243                 :     }                                                                                                                                                          
     244                 :                                                                                                                                                                
     245                 :     /**                                                                                                                                                        
     246                 :      * Removes comments in the query string. Comments are                                                                                                      
     247                 :      * indicated by '#'.                                                                                                                                       
     248                 :      *                                                                                                                                                         
     249                 :      * @param  string $queryString                                                                                                                             
     250                 :      * @return string The uncommented query string                                                                                                             
     251                 :      */                                                                                                                                                        
     252                 :     public static function uncomment($queryString)                                                                                                             
     253                 :     {                                                                                                                                                          
     254             335 :         $regex = "/((\"[^\"]*\")|(\'[^\']*\')|(\<[^\>]*\>))|(#.*)/";                                                                                           
     255                 :                                                                                                                                                                
     256             335 :         return preg_replace($regex, '\1', $queryString);                                                                                                       
     257                 :     }                                                                                                                                                          
     258                 :                                                                                                                                                                
     259                 :     // ------------------------------------------------------------------------                                                                                
     260                 :     // --- Protected static methods -------------------------------------------                                                                                
     261                 :     // ------------------------------------------------------------------------                                                                                
     262                 :                                                                                                                                                                
     263                 :     /**                                                                                                                                                        
     264                 :      *   "Balances" the filter tree in the way that operators on the same                                                                                      
     265                 :      *   level are nested according to their precedence defined in                                                                                             
     266                 :      *   $operatorPrecedence array.                                                                                                                            
     267                 :      *                                                                                                                                                         
     268                 :      *   @param array $tree  Tree to be modified                                                                                                               
     269                 :      */                                                                                                                                                        
     270                 :     public static function balanceTree(&$tree)                                                                                                                 
     271                 :     {                                                                                                                                                          
     272                 :                                                                                                                                                                
     273              46 :         if (isset($tree['type']) && $tree['type'] === 'equation' && isset($tree['operand1']['type']) &&                                                        
     274              46 :             $tree['operand1']['type'] === 'equation' && $tree['level'] === $tree['operand1']['level'] &&                                                       
     275              46 :             self::$_operatorPrecedence[$tree['operator']] > self::$_operatorPrecedence[$tree['operand1']['operator']]) {                                       
     276                 :                                                                                                                                                                
     277                 :             $op2 = array(                                                                                                                                      
     278               4 :                 'type'      => 'equation',                                                                                                                     
     279               4 :                 'level'     => $tree['level'],                                                                                                                 
     280               4 :                 'operator'  => $tree['operator'],                                                                                                              
     281               4 :                 'operand1'  => $tree['operand1']['operand2'],                                                                                                  
     282               4 :                 'operand2'  => $tree['operand2']                                                                                                               
     283               4 :             );                                                                                                                                                 
     284               4 :             $tree['operator']   = $tree['operand1']['operator'];                                                                                               
     285               4 :             $tree['operand1']   = $tree['operand1']['operand1'];                                                                                               
     286               4 :             $tree['operand2']   = $op2;                                                                                                                        
     287               4 :         }                                                                                                                                                      
     288              46 :     }                                                                                                                                                          
     289                 :                                                                                                                                                                
     290                 :     public static function fixNegationInFuncName(&$tree)                                                                                                       
     291                 :     {                                                                                                                                                          
     292              60 :         if ($tree['type'] === 'function' && $tree['name'][0] === '!') {                                                                                        
     293               4 :             $tree['name'] = substr($tree['name'], 1);                                                                                                          
     294                 :                                                                                                                                                                
     295               4 :             if (!isset($tree['negated'])) {                                                                                                                    
     296               4 :                 $tree['negated'] = true;                                                                                                                       
     297               4 :             } else {                                                                                                                                           
     298               0 :                 unset($tree['negated']);                                                                                                                       
     299                 :             }                                                                                                                                                  
     300                 :             //perhaps more !!                                                                                                                                  
     301               4 :             self::fixNegationInFuncName($tree);                                                                                                                
     302               4 :         }                                                                                                                                                      
     303              60 :     }                                                                                                                                                          
     304                 :                                                                                                                                                                
     305                 :     // ------------------------------------------------------------------------                                                                                
     306                 :     // --- Public methods -----------------------------------------------------                                                                                
     307                 :     // ------------------------------------------------------------------------                                                                                
     308                 :                                                                                                                                                                
     309                 :     /**                                                                                                                                                        
     310                 :      * Main function of Erfurt_Sparql_Parser.                                                                                                                  
     311                 :      * Parses a query string.                                                                                                                                  
     312                 :      *                                                                                                                                                         
     313                 :      * @param string $queryString The SPARQL query                                                                                                             
     314                 :      * @return Erfurt_Sparql_Query The query object                                                                                                            
     315                 :      * @throws Erfurt_Sparql_ParserException                                                                                                                   
     316                 :      */                                                                                                                                                        
     317                 :     public function parse($queryString = false)                                                                                                                
     318                 :     {                                                                                                                                                          
     319             334 :         if ($queryString === false) {                                                                                                                          
     320               0 :             require_once 'Erfurt/Sparql/ParserException.php';                                                                                                  
     321               0 :             throw new Erfurt_Sparql_ParserException('Querystring is empty.');                                                                                  
     322                 :         }                                                                                                                                                      
     323                 :         //echo "Parser is called on:\n".$queryString."\n\n";                                                                                                   
     324             334 :         $this->_prepare();                                                                                                                                     
     325             334 :         $this->_query->setQueryString($queryString);                                                                                                           
     326                 :                                                                                                                                                                
     327             334 :         $uncommented = self::uncomment($queryString);                                                                                                          
     328             334 :         $this->_tokens = self::tokenize($uncommented);                                                                                                         
     329                 :                                                                                                                                                                
     330             334 :         $this->_parseQuery();                                                                                                                                  
     331                 :                                                                                                                                                                
     332             334 :         if (!$this->_query->isComplete()) {                                                                                                                    
     333               0 :             require_once 'Erfurt/Sparql/ParserException.php';                                                                                                  
     334               0 :             throw new Erfurt_Sparql_ParserException('Query is incomplete.');                                                                                   
     335                 :         }                                                                                                                                                      
     336                 :                                                                                                                                                                
     337             334 :         return $this->_query;                                                                                                                                  
     338                 :     }                                                                                                                                                          
     339                 :                                                                                                                                                                
     340                 :     // ------------------------------------------------------------------------                                                                                
     341                 :     // --- Protected methods --------------------------------------------------                                                                                
     342                 :     // ------------------------------------------------------------------------                                                                                
     343                 :                                                                                                                                                                
     344                 :     /**                                                                                                                                                        
     345                 :      * Checks if $token is a Blanknode.                                                                                                                        
     346                 :      *                                                                                                                                                         
     347                 :      * @param  string  $token The token                                                                                                                        
     348                 :      * @return boolean true if the token is BNode false if not                                                                                                 
     349                 :      */                                                                                                                                                        
     350                 :     protected function _bNodeCheck($token)                                                                                                                     
     351                 :     {                                                                                                                                                          
     352             314 :         if (substr($token, 0, 2) === '_:') {                                                                                                                   
     353              30 :             return true;                                                                                                                                       
     354                 :         }                                                                                                                                                      
     355                 :                                                                                                                                                                
     356             312 :         return false;                                                                                                                                          
     357                 :     }                                                                                                                                                          
     358                 :                                                                                                                                                                
     359                 :     /**                                                                                                                                                        
     360                 :      * Checks if there is a datatype given and appends it to the node.                                                                                         
     361                 :      *                                                                                                                                                         
     362                 :      * @param string $node Node to check                                                                                                                       
     363                 :      */                                                                                                                                                        
     364                 :     protected function _checkDtypeLang(&$node, $nSubstrLength = 1)                                                                                             
     365                 :     {                                                                                                                                                          
     366              45 :         $this->_fastForward();                                                                                                                                 
     367              45 :         switch (substr(current($this->_tokens), 0, 1)) {                                                                                                       
     368              45 :             case '^':                                                                                                                                          
     369               6 :                 if (substr(current($this->_tokens), 0, 2) === '^^') {                                                                                          
     370               6 :                     if (strlen(current($this->_tokens)) === 2) {                                                                                               
     371               1 :                         next($this->_tokens);                                                                                                                  
     372               1 :                     }                                                                                                                                          
     373                 :                                                                                                                                                                
     374               6 :                     require_once 'Erfurt/Rdf/Literal.php';                                                                                                     
     375               6 :                     $node = Erfurt_Rdf_Literal::initWithLabel(substr($node, 1, -1));                                                                           
     376               6 :                     $node->setDatatype(                                                                                                                        
     377               6 :                         $this->_query->getFullUri(                                                                                                             
     378               6 :                             substr(current($this->_tokens), 2)                                                                                                 
     379               6 :                         )                                                                                                                                      
     380               6 :                     );                                                                                                                                         
     381               6 :                 }                                                                                                                                              
     382               6 :                 break;                                                                                                                                         
     383              39 :             case '@':                                                                                                                                          
     384               1 :                 require_once 'Erfurt/Rdf/Literal.php';                                                                                                         
     385               1 :                 $node = Erfurt_Rdf_Literal::initWithLabelAndLanguage(                                                                                          
     386               1 :                     substr($node, $nSubstrLength, -$nSubstrLength),                                                                                            
     387               1 :                     substr(current($this->_tokens), $nSubstrLength)                                                                                            
     388               1 :                 );                                                                                                                                             
     389               1 :                 break;                                                                                                                                         
     390              38 :             default:                                                                                                                                           
     391              38 :                 prev($this->_tokens);                                                                                                                          
     392              38 :                 require_once 'Erfurt/Rdf/Literal.php';                                                                                                         
     393              38 :                 $node = Erfurt_Rdf_Literal::initWithLabel(substr($node, $nSubstrLength, -$nSubstrLength));                                                     
     394              38 :                 break;                                                                                                                                         
     395              45 :         }                                                                                                                                                      
     396              45 :     }                                                                                                                                                          
     397                 :                                                                                                                                                                
     398                 :                                                                                                                                                                
     399                 :     protected function _dissallowBlankNodes()                                                                                                                  
     400                 :     {                                                                                                                                                          
     401             333 :         foreach ($this->_usedBlankNodes as $key => &$value) {                                                                                                  
     402              30 :             $value = false;                                                                                                                                    
     403             333 :         }                                                                                                                                                      
     404             333 :     }                                                                                                                                                          
     405                 :                                                                                                                                                                
     406                 :     /**                                                                                                                                                        
     407                 :      * Checks if the Node is a typed Literal.                                                                                                                  
     408                 :      *                                                                                                                                                         
     409                 :      * @param String $node                                                                                                                                     
     410                 :      * @return boolean true if typed, false if not.                                                                                                            
     411                 :      */                                                                                                                                                        
     412                 :     protected function _dtypeCheck(&$node)                                                                                                                     
     413                 :     {                                                                                                                                                          
     414             314 :         $patternInt = "/^-?[0-9]+$/";                                                                                                                          
     415             314 :         $match = preg_match($patternInt,$node,$hits);                                                                                                          
     416             314 :         if ($match > 0) {                                                                                                                                      
     417              13 :             require_once 'Erfurt/Rdf/Literal.php';                                                                                                             
     418              13 :             $node = Erfurt_Rdf_Literal::initWithLabel($hits[0]);                                                                                               
     419              13 :             $node->setDatatype(EF_XSD_NS.'integer');                                                                                                           
     420              13 :             return true;                                                                                                                                       
     421                 :         }                                                                                                                                                      
     422                 :                                                                                                                                                                
     423             314 :         $patternBool = "/^(true|false)$/";                                                                                                                     
     424             314 :         $match = preg_match($patternBool,$node,$hits);                                                                                                         
     425             314 :         if ($match>0) {                                                                                                                                        
     426               0 :             require_once 'Erfurt/Rdf/Literal.php';                                                                                                             
     427               0 :             $node = Erfurt_Rdf_Literal::initWithLabel($hits[0]);                                                                                               
     428               0 :             $node->setDatatype(EF_XSD_NS.'boolean');                                                                                                           
     429               0 :             return true;                                                                                                                                       
     430                 :         }                                                                                                                                                      
     431                 :                                                                                                                                                                
     432             314 :         $patternType = "/^a$/";                                                                                                                                
     433             314 :         $match = preg_match($patternType,$node,$hits);                                                                                                         
     434             314 :         if ($match>0) {                                                                                                                                        
     435               9 :             require_once 'Erfurt/Rdf/Resource.php';                                                                                                            
     436               9 :             $node = Erfurt_Rdf_Resource::initWithNamespaceAndLocalName(EF_RDF_NS, 'type');                                                                     
     437               9 :             return true;                                                                                                                                       
     438                 :         }                                                                                                                                                      
     439                 :                                                                                                                                                                
     440             314 :         $patternDouble = "/^-?[0-9]+.[0-9]+[e|E]?-?[0-9]*/";                                                                                                   
     441             314 :         $match = preg_match($patternDouble,$node,$hits);                                                                                                       
     442             314 :         if ($match>0) {                                                                                                                                        
     443               6 :             require_once 'Erfurt/Rdf/Literal.php';                                                                                                             
     444               6 :             $node = Erfurt_Rdf_Literal::initWithLabel($hits[0]);                                                                                               
     445               6 :             $node->setDatatype(EF_XSD_NS.'double');                                                                                                            
     446               6 :             return true;                                                                                                                                       
     447                 :         }                                                                                                                                                      
     448             314 :         return false;                                                                                                                                          
     449                 :     }                                                                                                                                                          
     450                 :                                                                                                                                                                
     451                 :     /** FastForward until next token which is not blank. */                                                                                                    
     452                 :     protected function _fastForward()                                                                                                                          
     453                 :     {                                                                                                                                                          
     454                 :         #next($this->_tokens);                                                                                                                                 
     455                 :         #return;                                                                                                                                               
     456                 :                                                                                                                                                                
     457             334 :         $tok = next($this->_tokens);                                                                                                                           
     458             334 :         while ($tok === ' ') {                                                                                                                                 
     459               3 :             $tok = next($this->_tokens);                                                                                                                       
     460               3 :         }                                                                                                                                                      
     461             334 :     }                                                                                                                                                          
     462                 :                                                                                                                                                                
     463                 :     /**                                                                                                                                                        
     464                 :      * Checks if $token is an IRI.                                                                                                                             
     465                 :      *                                                                                                                                                         
     466                 :      * @param  string  $token The token                                                                                                                        
     467                 :      * @return boolean true if the token is an IRI false if not                                                                                                
     468                 :      */                                                                                                                                                        
     469                 :     protected function _iriCheck($token)                                                                                                                       
     470                 :     {                                                                                                                                                          
     471             326 :         $pattern = "/^<[^>]*>\.?$/";                                                                                                                           
     472                 :                                                                                                                                                                
     473             326 :         if (preg_match($pattern, $token) > 0) {                                                                                                                
     474             257 :             return true;                                                                                                                                       
     475                 :         }                                                                                                                                                      
     476                 :                                                                                                                                                                
     477             305 :         return false;                                                                                                                                          
     478                 :     }                                                                                                                                                          
     479                 :                                                                                                                                                                
     480                 :     /**                                                                                                                                                        
     481                 :      * Checks if $token is a Literal.                                                                                                                          
     482                 :      *                                                                                                                                                         
     483                 :      * @param string $token The token                                                                                                                          
     484                 :      * @return boolean true if the token is a Literal false if not                                                                                             
     485                 :      */                                                                                                                                                        
     486                 :     protected function _literalCheck($token)                                                                                                                   
     487                 :     {                                                                                                                                                          
     488             268 :         $pattern = "/^[\"\'].*$/";                                                                                                                             
     489             268 :         if (preg_match($pattern, $token) > 0) {                                                                                                                
     490              45 :             return true;                                                                                                                                       
     491             246 :         } else if (is_numeric($token)) {                                                                                                                       
     492               3 :             return true;                                                                                                                                       
     493                 :         }                                                                                                                                                      
     494                 :                                                                                                                                                                
     495             243 :         return false;                                                                                                                                          
     496                 :     }                                                                                                                                                          
     497                 :                                                                                                                                                                
     498                 :     /**                                                                                                                                                        
     499                 :      * Sets result form to 'ASK' and 'COUNT'.                                                                                                                  
     500                 :      *                                                                                                                                                         
     501                 :      * @param string $form  if it's an ASK or COUNT query                                                                                                      
     502                 :      */                                                                                                                                                        
     503                 :     protected function _parseAsk($form)                                                                                                                        
     504                 :     {                                                                                                                                                          
     505               7 :         $this->_query->setResultForm($form);                                                                                                                   
     506                 :                                                                                                                                                                
     507               7 :         $this->_fastForward();                                                                                                                                 
     508                 :                                                                                                                                                                
     509               7 :         if (current($this->_tokens) === '{' || strtolower(current($this->_tokens)) === 'from') {                                                               
     510               7 :             prev($this->_tokens);                                                                                                                              
     511               7 :         }                                                                                                                                                      
     512               7 :     }                                                                                                                                                          
     513                 :                                                                                                                                                                
     514                 :     /**                                                                                                                                                        
     515                 :      * Parses the BASE part of the query.                                                                                                                      
     516                 :      *                                                                                                                                                         
     517                 :      * @throws Erfurt_Sparql_ParserException                                                                                                                   
     518                 :      */                                                                                                                                                        
     519                 :     protected function _parseBase()                                                                                                                            
     520                 :     {                                                                                                                                                          
     521              28 :         $this->_fastForward();                                                                                                                                 
     522              28 :         if ($this->_iriCheck(current($this->_tokens))) {                                                                                                       
     523              28 :             $this->_query->setBase(current($this->_tokens));                                                                                                   
     524              28 :         } else {                                                                                                                                               
     525               0 :             require_once 'Erfurt/Sparql/ParserException.php';                                                                                                  
     526               0 :             throw new Erfurt_Sparql_ParserException('IRI expected', -1, key($this->_tokens));                                                                  
     527                 :         }                                                                                                                                                      
     528              28 :     }                                                                                                                                                          
     529                 :                                                                                                                                                                
     530                 :     /**                                                                                                                                                        
     531                 :      * Parses an RDF collection.                                                                                                                               
     532                 :      *                                                                                                                                                         
     533                 :      * @param  Erfurt_Sparql_TriplePattern $trp                                                                                                                
     534                 :      * @return Erfurt_Rdf_Node The first parsed label.                                                                                                         
     535                 :      */                                                                                                                                                        
     536                 :     protected function _parseCollection(&$trp)                                                                                                                 
     537                 :     {                                                                                                                                                          
     538              12 :         if (prev($this->_tokens) === '{') {                                                                                                                    
     539              11 :             $prevStart = true;                                                                                                                                 
     540              11 :         } else {                                                                                                                                               
     541               4 :             $prevStart = false;                                                                                                                                
     542                 :         }                                                                                                                                                      
     543              12 :         next($this->_tokens);                                                                                                                                  
     544                 :                                                                                                                                                                
     545              12 :         $tmpLabel = $this->_query->getBlanknodeLabel();                                                                                                        
     546              12 :         $firstLabel = $this->_parseNode($tmpLabel);                                                                                                            
     547              12 :         $this->_fastForward();                                                                                                                                 
     548              12 :         $i = 0;                                                                                                                                                
     549              12 :         $emptyList = true;                                                                                                                                     
     550                 :                                                                                                                                                                
     551              12 :         require_once 'Erfurt/Rdf/Resource.php';                                                                                                                
     552              12 :         $rdfRest    = Erfurt_Rdf_Resource::initWithNamespaceAndLocalName(EF_RDF_NS, 'rest');                                                                   
     553              12 :         $rdfFirst   = Erfurt_Rdf_Resource::initWithNamespaceAndLocalName(EF_RDF_NS, 'first');                                                                  
     554              12 :         $rdfNil     = Erfurt_Rdf_Resource::initWithNamespaceAndLocalName(EF_RDF_NS, 'nil');                                                                    
     555                 :                                                                                                                                                                
     556              12 :         require_once 'Erfurt/Sparql/QueryTriple.php';                                                                                                          
     557              12 :         while (current($this->_tokens) !== ')') {                                                                                                              
     558               9 :             if ($i>0) {                                                                                                                                        
     559               4 :                 $trp[] = new Erfurt_Sparql_QueryTriple($this->_parseNode($tmpLabel), $rdfRest,                                                                 
     560               4 :                                 $this->_parseNode($tmpLabel = $this->_query->getBlanknodeLabel()));                                                            
     561               4 :             }                                                                                                                                                  
     562                 :                                                                                                                                                                
     563               9 :             if (current($this->_tokens) === '(') {                                                                                                             
     564               2 :                 $listNode = $this->_parseCollection($trp);                                                                                                     
     565                 :                                                                                                                                                                
     566               2 :                 $trp[] = new Erfurt_Sparql_QueryTriple($this->_parseNode($tmpLabel), $rdfFirst, $listNode);                                                    
     567               9 :             } else if (current($this->_tokens) === '[') {                                                                                                      
     568               2 :                 $this->_fastForward();                                                                                                                         
     569               2 :                 if (current($this->_tokens) === ']') {                                                                                                         
     570               1 :                     $this->_rewind();                                                                                                                          
     571               1 :                     $trp[] = new Erfurt_Sparql_QueryTriple($this->_parseNode($tmpLabel), $rdfFirst, $this->_parseNode());                                      
     572               1 :                 } else {                                                                                                                                       
     573               1 :                     $this->_rewind();                                                                                                                          
     574                 :                                                                                                                                                                
     575               1 :                     $sNode = $this->_parseNode();                                                                                                              
     576               1 :                     $trp[] = new Erfurt_Sparql_QueryTriple($this->_parseNode($tmpLabel), $rdfFirst, $sNode);                                                   
     577                 :                                                                                                                                                                
     578               1 :                     $this->_fastForward();                                                                                                                     
     579               1 :                     $p =  $this->_parseNode();                                                                                                                 
     580                 :                                                                                                                                                                
     581               1 :                     $this->_fastForward();                                                                                                                     
     582               1 :                     $o = $this->_parseNode();                                                                                                                  
     583                 :                                                                                                                                                                
     584               1 :                     $trp[] = new Erfurt_Sparql_QueryTriple($sNode, $p, $o);                                                                                    
     585               1 :                     $this->_fastForward();                                                                                                                     
     586                 :                 }                                                                                                                                              
     587               2 :             } else {                                                                                                                                           
     588               7 :                 $trp[] = new Erfurt_Sparql_QueryTriple($this->_parseNode($tmpLabel), $rdfFirst, $this->_parseNode());                                          
     589                 :             }                                                                                                                                                  
     590                 :                                                                                                                                                                
     591               9 :             $this->_fastForward();                                                                                                                             
     592               9 :             $emptyList = false;                                                                                                                                
     593               9 :             $i++;                                                                                                                                              
     594               9 :         }                                                                                                                                                      
     595                 :                                                                                                                                                                
     596              12 :         if ($prevStart && $emptyList) {                                                                                                                        
     597               3 :             if (next($this->_tokens) === '}') {                                                                                                                
     598                 :                 // list may not occure standalone in a pattern.                                                                                                
     599               0 :                 require_once 'Erfurt/Sparql/ParserException.php';                                                                                              
     600               0 :                 throw new Erfurt_Sparql_ParserException(                                                                                                       
     601               0 :                     'A list may not occur standalone in a pattern.', -1, key($this->_tokens));                                                                 
     602                 :             }                                                                                                                                                  
     603               3 :             prev($this->_tokens);                                                                                                                              
     604               3 :         }                                                                                                                                                      
     605                 :                                                                                                                                                                
     606              12 :         $trp[] = new Erfurt_Sparql_QueryTriple($this->_parseNode($tmpLabel), $rdfRest, $rdfNil);                                                               
     607              12 :         return $firstLabel;                                                                                                                                    
     608                 :     }                                                                                                                                                          
     609                 :                                                                                                                                                                
     610                 :     /**                                                                                                                                                        
     611                 :      * Parses a value constraint.                                                                                                                              
     612                 :      *                                                                                                                                                         
     613                 :      * @param GraphPattern $pattern                                                                                                                            
     614                 :      * @param boolean $outer If the constraint is an outer one.                                                                                                
     615                 :      */                                                                                                                                                        
     616                 :     protected function _parseConstraint(&$pattern, $outer)                                                                                                     
     617                 :     {                                                                                                                                                          
     618              91 :         require_once 'Erfurt/Sparql/Constraint.php';                                                                                                           
     619              91 :         $constraint = new Erfurt_Sparql_Constraint();                                                                                                          
     620              91 :         $constraint->setOuterFilter($outer);                                                                                                                   
     621                 :                                                                                                                                                                
     622              91 :         $constraint->setTree($this->_parseConstraintTree());                                                                                                   
     623                 :                                                                                                                                                                
     624              91 :         if (current($this->_tokens) === '}') {                                                                                                                 
     625              49 :             prev($this->_tokens);                                                                                                                              
     626              49 :         }                                                                                                                                                      
     627                 :                                                                                                                                                                
     628              91 :         $pattern->addConstraint($constraint);                                                                                                                  
     629              91 :     }                                                                                                                                                          
     630                 :                                                                                                                                                                
     631                 :     /**                                                                                                                                                        
     632                 :      *   Parses a constraint string recursively.                                                                                                               
     633                 :      *                                                                                                                                                         
     634                 :      *   The result array is one "element" which may contain subelements.                                                                                      
     635                 :      *   All elements have one key "type" that determines which other                                                                                          
     636                 :      *   array keys the element array has. Valid types are:                                                                                                    
     637                 :      *   - "value":                                                                                                                                            
     638                 :      *       Just a plain value with a value key, nothing else                                                                                                 
     639                 :      *   - "function"                                                                                                                                          
     640                 :      *       A function has a name and an array of parameter(s). Each parameter                                                                                
     641                 :      *       is an element.                                                                                                                                    
     642                 :      *   - "equation"                                                                                                                                          
     643                 :      *       An equation has an operator, and operand1 and operand2 which                                                                                      
     644                 :      *       are elements themselves                                                                                                                           
     645                 :      *   Any element may have the "negated" value set to true, which means                                                                                     
     646                 :      *   that is is - negated (!).                                                                                                                             
     647                 :      *                                                                                                                                                         
     648                 :      *   @internal The functionality of this method is being unit-tested                                                                                       
     649                 :      *   in testSparqlParserTests::testParseFilter()                                                                                                           
     650                 :      *   "equation'-elements have another key "level" which is to be used                                                                                      
     651                 :      *   internally only.                                                                                                                                      
     652                 :      *                                                                                                                                                         
     653                 :      *   @return array Nested tree array representing the filter                                                                                               
     654                 :      */                                                                                                                                                        
     655                 :     protected function _parseConstraintTree($nLevel = 0, $bParameter = false)                                                                                  
     656                 :     {                                                                                                                                                          
     657              91 :         $tree       = array();                                                                                                                                 
     658              91 :         $part       = array();                                                                                                                                 
     659              91 :         $chQuotes   = null;                                                                                                                                    
     660              91 :         $litQuotes  = null;                                                                                                                                    
     661              91 :         $strQuoted  = '';                                                                                                                                      
     662              91 :         $parens     = false;                                                                                                                                   
     663                 :                                                                                                                                                                
     664              91 :         while ($tok = next($this->_tokens)) {                                                                                                                  
     665              91 :             if ($chQuotes !== null && $tok != $chQuotes) {                                                                                                     
     666              31 :                 $strQuoted .= $tok;                                                                                                                            
     667              31 :                 continue;                                                                                                                                      
     668              91 :             } else if ($litQuotes !== null) {                                                                                                                  
     669               0 :                 $strQuoted .= $tok;                                                                                                                            
     670               0 :                 if ($tok[strlen($tok) - 1] === '>') {                                                                                                          
     671               0 :                     $tok = '>';                                                                                                                                
     672               0 :                 } else {                                                                                                                                       
     673               0 :                     continue;                                                                                                                                  
     674                 :                 }                                                                                                                                              
     675              91 :             } else if ($tok === ')' || $tok === '}' || $tok === '.') {                                                                                         
     676              91 :                 break;                                                                                                                                         
     677              91 :             } else if (strtolower($tok) === 'filter' || strtolower($tok) === 'optional') {                                                                     
     678               6 :                 break;                                                                                                                                         
     679                 :             }                                                                                                                                                  
     680                 :             switch ($tok) {                                                                                                                                    
     681              91 :                 case '"':                                                                                                                                      
     682              91 :                 case '\'':                                                                                                                                     
     683              32 :                     if ($chQuotes === null) {                                                                                                                  
     684              32 :                         $chQuotes  = $tok;                                                                                                                     
     685              32 :                         $strQuoted = '';                                                                                                                       
     686              32 :                     } else {                                                                                                                                   
     687              32 :                         $chQuotes = null;                                                                                                                      
     688              32 :                         $part[] = array(                                                                                                                       
     689              32 :                             'type'  => 'value',                                                                                                                
     690              32 :                             'value' => $strQuoted,                                                                                                             
     691                 :                             'quoted'=> true                                                                                                                    
     692              32 :                         );                                                                                                                                     
     693                 :                     }                                                                                                                                          
     694              32 :                     continue 2;                                                                                                                                
     695                 :                     break;                                                                                                                                     
     696                 : #                case '>':                                                                                                                                     
     697                 : #                   $litQuotes = null;                                                                                                                         
     698                 : #                    $part[] = array(                                                                                                                          
     699                 : #                        'type'  => 'value',                                                                                                                   
     700                 : #                        'value' => $strQuoted,                                                                                                                
     701                 : #                        'quoted'=> false                                                                                                                      
     702                 : #                    );                                                                                                                                        
     703                 : #                    continue 2;                                                                                                                               
     704                 : #                    break;                                                                                                                                    
     705              91 :                 case '(':                                                                                                                                      
     706              91 :                     $parens = true;                                                                                                                            
     707              91 :                     $bFunc1 = isset($part[0]['type']) && $part[0]['type'] === 'value';                                                                         
     708              91 :                     $bFunc2 = isset($tree['type']) && $tree['type'] === 'equation'                                                                             
     709              91 :                            && isset($tree['operand2']) && isset($tree['operand2']['value']);                                                                   
     710              91 :                     $part[] = $this->_parseConstraintTree(                                                                                                     
     711              91 :                         $nLevel + 1,                                                                                                                           
     712               0 :                         $bFunc1 || $bFunc2                                                                                                                     
     713              91 :                     );                                                                                                                                         
     714                 :                                                                                                                                                                
     715              91 :                     if ($bFunc1) {                                                                                                                             
     716              58 :                         $tree['type'] = 'function';                                                                                                            
     717              58 :                         $tree['name'] = $part[0]['value'];                                                                                                     
     718              58 :                         self::fixNegationInFuncName($tree);                                                                                                    
     719              58 :                         if (isset($part[1]['type'])) {                                                                                                         
     720               0 :                             $part[1] = array($part[1]);                                                                                                        
     721               0 :                         }                                                                                                                                      
     722              58 :                         $tree['parameter'] = $part[1];                                                                                                         
     723              58 :                         $part = array();                                                                                                                       
     724              91 :                     } else if ($bFunc2) {                                                                                                                      
     725              11 :                         $tree['operand2']['type'] = 'function';                                                                                                
     726              11 :                         $tree['operand2']['name'] = $tree['operand2']['value'];                                                                                
     727              11 :                         self::fixNegationInFuncName($tree['operand2']);                                                                                        
     728              11 :                         $tree['operand2']['parameter']  = $part[0];                                                                                            
     729              11 :                         unset($tree['operand2']['value']);                                                                                                     
     730              11 :                         unset($tree['operand2']['quoted']);                                                                                                    
     731              11 :                         $part = array();                                                                                                                       
     732              11 :                     }                                                                                                                                          
     733                 :                                                                                                                                                                
     734              91 :                     if (current($this->_tokens) === ')') {                                                                                                     
     735              90 :                         if (substr(next($this->_tokens), 0, 2) === '_:') {                                                                                     
     736                 :                             // filter ends here                                                                                                                
     737               1 :                             prev($this->_tokens);                                                                                                              
     738               1 :                             break 2;                                                                                                                           
     739                 :                         } else {                                                                                                                               
     740              89 :                             prev($this->_tokens);                                                                                                              
     741                 :                         }                                                                                                                                      
     742              89 :                     }                                                                                                                                          
     743                 :                                                                                                                                                                
     744              90 :                     continue 2;                                                                                                                                
     745                 :                     break;                                                                                                                                     
     746              91 :                 case ' ':                                                                                                                                      
     747              91 :                 case "\t":                                                                                                                                     
     748               0 :                     continue 2;                                                                                                                                
     749              91 :                 case '=':                                                                                                                                      
     750              91 :                 case '>':                                                                                                                                      
     751              91 :                 case '<':                                                                                                                                      
     752              91 :                 case '<=':                                                                                                                                     
     753              91 :                 case '>=':                                                                                                                                     
     754              91 :                 case '-' : //TODO: check correctness                                                                                                           
     755              91 :                 case '+' : //TODO: check correctness                                                                                                           
     756              91 :                 case '!=':                                                                                                                                     
     757              91 :                 case '&&':                                                                                                                                     
     758              91 :                 case '||':                                                                                                                                     
     759              46 :                     if (isset($tree['type']) && $tree['type'] === 'equation' && isset($tree['operand2'])) {                                                    
     760                 :                         //previous equation open                                                                                                               
     761               4 :                         $part = array($tree);                                                                                                                  
     762              46 :                     } else if (isset($tree['type']) && $tree['type'] !== 'equation') {                                                                         
     763              23 :                         $part = array($tree);                                                                                                                  
     764              23 :                         $tree = array();                                                                                                                       
     765              23 :                     }                                                                                                                                          
     766                 :                                                                                                                                                                
     767              46 :                     $tree['type'] = 'equation';                                                                                                                
     768              46 :                     $tree['level'] = $nLevel;                                                                                                                  
     769              46 :                     $tree['operator'] = $tok;                                                                                                                  
     770                 :                     //TODO: remove the if when parse contraint is fixed (issue 601)                                                                            
     771              46 :                     if(isset($part[0])) $tree['operand1'] = $part[0]; else $tree['operand1'] = null;                                                           
     772              46 :                     unset($tree['operand2']);                                                                                                                  
     773              46 :                     $part = array();                                                                                                                           
     774              46 :                     continue 2;                                                                                                                                
     775                 :                     break;                                                                                                                                     
     776              91 :                 case '!':                                                                                                                                      
     777               6 :                     if ($tree != array()) {                                                                                                                    
     778               0 :                         require_once 'Erfurt/Sparql/ParserException.php';                                                                                      
     779               0 :                         throw new Erfurt_Sparql_ParserException(                                                                                               
     780               0 :                             'Unexpected "!" negation in constraint.', -1, current($this->_tokens));                                                            
     781                 :                     }                                                                                                                                          
     782               6 :                     $tree['negated'] = true;                                                                                                                   
     783               6 :                     continue 2;                                                                                                                                
     784              91 :                 case ',':                                                                                                                                      
     785                 :                     //parameter separator                                                                                                                      
     786              21 :                     if (count($part) == 0 && !isset($tree['type'])) {                                                                                          
     787               0 :                         throw new SparqlParserException(                                                                                                       
     788                 :                             'Unexpected comma'                                                                                                                 
     789               0 :                         );                                                                                                                                     
     790                 :                     }                                                                                                                                          
     791              21 :                     $bParameter = true;                                                                                                                        
     792              21 :                     if (count($part) === 0) {                                                                                                                  
     793               6 :                         $part[] = $tree;                                                                                                                       
     794               6 :                         $tree = array();                                                                                                                       
     795               6 :                     }                                                                                                                                          
     796              21 :                     continue 2;                                                                                                                                
     797              91 :                 default:                                                                                                                                       
     798              91 :                     break;                                                                                                                                     
     799              91 :             }                                                                                                                                                  
     800                 :                                                                                                                                                                
     801              91 :             if ($this->_varCheck($tok)) {                                                                                                                      
     802              86 :                 if (!$parens && $nLevel === 0) {                                                                                                               
     803                 :                     // Variables need parenthesizes first                                                                                                      
     804               0 :                     require_once 'Erfurt/Sparql/ParserException.php';                                                                                          
     805               0 :                     throw new Erfurt_Sparql_ParserException('FILTER expressions that start with a variable need parenthesizes.', -1, current($this->_tokens)); 
     806                 :                 }                                                                                                                                              
     807                 :                                                                                                                                                                
     808              86 :                 $part[] = array(                                                                                                                               
     809              86 :                     'type'      => 'value',                                                                                                                    
     810              86 :                     'value'     => $tok,                                                                                                                       
     811                 :                     'quoted'    => false                                                                                                                       
     812              86 :                 );                                                                                                                                             
     813              91 :             } else if (substr($tok, 0, 2) === '_:') {                                                                                                          
     814                 :                 // syntactic blank nodes not allowed in filter                                                                                                 
     815               0 :                 require_once 'Erfurt/Sparql/ParserException.php';                                                                                              
     816               0 :                 throw new Erfurt_Sparql_ParserException('Syntactic Blanknodes not allowed in FILTER.', -1,                                                     
     817               0 :                                 current($this->_tokens));                                                                                                      
     818              73 :             } else if (substr($tok, 0, 2) === '^^') {                                                                                                          
     819               2 :                 $part[count($part) - 1]['datatype'] = $this->_query->getFullUri(substr($tok, 2));                                                              
     820              73 :             } else if ($tok[0] === '@') {                                                                                                                      
     821               2 :                 $part[count($part) - 1]['language'] = substr($tok, 1);                                                                                         
     822              71 :             } else if ($tok[0] === '<') {                                                                                                                      
     823              15 :                 if ($tok[strlen($tok) - 1] === '>') {                                                                                                          
     824                 :                     //single-tokenized <> uris                                                                                                                 
     825              15 :                     $part[] = array(                                                                                                                           
     826              15 :                         'type'      => 'value',                                                                                                                
     827              15 :                         'value'     => $tok,                                                                                                                   
     828                 :                         'quoted'    => false                                                                                                                   
     829              15 :                     );                                                                                                                                         
     830              15 :                 } else {                                                                                                                                       
     831                 :                     //iris split over several tokens                                                                                                           
     832               0 :                     $strQuoted = $tok;                                                                                                                         
     833               0 :                     $litQuotes = true;                                                                                                                         
     834                 :                 }                                                                                                                                              
     835              70 :             } else if ($tok === 'true' || $tok === 'false') {                                                                                                  
     836               2 :                 $part[] = array(                                                                                                                               
     837               2 :                     'type'      => 'value',                                                                                                                    
     838               2 :                     'value'     => $tok,                                                                                                                       
     839               2 :                     'quoted'    => false,                                                                                                                      
     840                 :                     'datatype'  => 'http://www.w3.org/2001/XMLSchema#boolean'                                                                                  
     841               2 :                 );                                                                                                                                             
     842               2 :             } else {                                                                                                                                           
     843              68 :                 $part[] = array(                                                                                                                               
     844              68 :                     'type'      => 'value',                                                                                                                    
     845              68 :                     'value'     => $tok,                                                                                                                       
     846                 :                     'quoted'    => false                                                                                                                       
     847              68 :                 );                                                                                                                                             
     848                 :             }                                                                                                                                                  
     849              91 :             if (isset($tree['type']) && $tree['type'] === 'equation' && isset($part[0])) {                                                                     
     850              35 :                 $tree['operand2'] = $part[0];                                                                                                                  
     851              35 :                 self::balanceTree($tree);                                                                                                                      
     852              35 :                 $part = array();                                                                                                                               
     853              35 :             }                                                                                                                                                  
     854              91 :         }                                                                                                                                                      
     855                 :                                                                                                                                                                
     856              91 :         if (!isset($tree['type']) && $bParameter) {                                                                                                            
     857              60 :             return $part;                                                                                                                                      
     858              91 :         } else if (isset($tree['type']) && $tree['type'] === 'equation'                                                                                        
     859              91 :             && isset($tree['operand1']) && !isset($tree['operand2'])                                                                                           
     860              91 :             && isset($part[0])) {                                                                                                                              
     861              15 :             $tree['operand2'] = $part[0];                                                                                                                      
     862              15 :             self::balanceTree($tree);                                                                                                                          
     863              15 :         }                                                                                                                                                      
     864                 :                                                                                                                                                                
     865              91 :         if ((count($tree) === 0) && (count($part) > 1)) {                                                                                                      
     866               0 :             require_once 'Erfurt/Sparql/ParserException.php';                                                                                                  
     867                 :             //TODO: uncomment when issue 601 is fixed                                                                                                          
     868                 :             //throw new Erfurt_Sparql_ParserException('Failed to parse constraint.', -1, current($this->_tokens));                                             
     869               0 :         }                                                                                                                                                      
     870                 :                                                                                                                                                                
     871              91 :         if (!isset($tree['type']) && isset($part[0])) {                                                                                                        
     872              73 :             if (isset($tree['negated'])) {                                                                                                                     
     873               3 :                 $part[0]['negated'] = true;                                                                                                                    
     874               3 :             }                                                                                                                                                  
     875              73 :             return $part[0];                                                                                                                                   
     876                 :         }                                                                                                                                                      
     877                 :                                                                                                                                                                
     878              80 :         return $tree;                                                                                                                                          
     879                 :     }                                                                                                                                                          
     880                 :                                                                                                                                                                
     881                 :     /**                                                                                                                                                        
     882                 :      * Parses the CONSTRUCT clause.                                                                                                                            
     883                 :      *                                                                                                                                                         
     884                 :      * @throws Erfurt_Sparql_ParserException                                                                                                                   
     885                 :      */                                                                                                                                                        
     886                 :     protected function _parseConstruct()                                                                                                                       
     887                 :     {                                                                                                                                                          
     888               9 :         $this->_fastForward();                                                                                                                                 
     889               9 :         $this->_query->setResultForm('construct');                                                                                                             
     890                 :                                                                                                                                                                
     891               9 :         if (current($this->_tokens) === '{') {                                                                                                                 
     892               9 :             $this->_parseGraphPattern(false, false, false, true);                                                                                              
     893               9 :         } else {                                                                                                                                               
     894               0 :             require_once 'Erfurt/Sparql/ParserException.php';                                                                                                  
     895               0 :             throw new Erfurt_Sparql_ParserException('Unable to parse CONSTRUCT part. "{" expected.', -1,                                                       
     896               0 :                             key($this->_tokens));                                                                                                              
     897                 :         }                                                                                                                                                      
     898                 :                                                                                                                                                                
     899               9 :         while (true) {                                                                                                                                         
     900               9 :             if (strtolower(current($this->_tokens)) === 'from') {                                                                                              
     901               0 :                 $this->_parseFrom();                                                                                                                           
     902               0 :             } else {                                                                                                                                           
     903               9 :                 break;                                                                                                                                         
     904                 :             }                                                                                                                                                  
     905               0 :         }                                                                                                                                                      
     906                 :                                                                                                                                                                
     907               9 :         $this->_parseWhere();                                                                                                                                  
     908               9 :         $this->_parseModifier();                                                                                                                               
     909               9 :     }                                                                                                                                                          
     910                 :                                                                                                                                                                
     911                 :     /** Adds a new variable to the query and sets result form to 'DESCRIBE'. */                                                                                
     912                 :     protected function _parseDescribe()                                                                                                                        
     913                 :     {                                                                                                                                                          
     914               2 :         while (strtolower(current($this->_tokens)) != 'from' && strtolower(current($this->_tokens)) != 'where') {                                              
     915               2 :             $this->_fastForward();                                                                                                                             
     916               2 :             if ($this->_varCheck(current($this->_tokens)) || $this->_iriCheck(current($this->_tokens))) {                                                      
     917               2 :                 require_once 'Erfurt/Sparql/QueryResultVariable.php';                                                                                          
     918               2 :                 $var = new Erfurt_Sparql_QueryResultVariable(current($this->_tokens));                                                                         
     919                 :                                                                                                                                                                
     920               2 :                 $this->_query->addResultVar($var);                                                                                                             
     921               2 :                 if (!$this->_query->getResultForm()) {                                                                                                         
     922               2 :                     $this->_query->setResultForm('describe');                                                                                                  
     923               2 :                 }                                                                                                                                              
     924               2 :             }                                                                                                                                                  
     925                 :                                                                                                                                                                
     926               2 :             if (!current($this->_tokens)) {                                                                                                                    
     927               1 :                 break;                                                                                                                                         
     928                 :             }                                                                                                                                                  
     929               2 :         }                                                                                                                                                      
     930               2 :         prev($this->_tokens);                                                                                                                                  
     931               2 :     }                                                                                                                                                          
     932                 :                                                                                                                                                                
     933                 :     /**                                                                                                                                                        
     934                 :      * Parses the FROM clause.                                                                                                                                 
     935                 :      *                                                                                                                                                         
     936                 :      * @throws Erfurt_Sparql_ParserException                                                                                                                   
     937                 :      */                                                                                                                                                        
     938                 :     protected function _parseFrom()                                                                                                                            
     939                 :     {                                                                                                                                                          
     940              25 :         $this->_fastForward();                                                                                                                                 
     941                 :                                                                                                                                                                
     942              25 :         if (strtolower(current($this->_tokens)) !== 'named') {                                                                                                 
     943              23 :             if ($this->_iriCheck(current($this->_tokens)) || $this->_qnameCheck(current($this->_tokens))) {                                                    
     944              23 :                 $this->_query->addFrom(substr(current($this->_tokens), 1, -1));                                                                                
     945              23 :             } else if ($this->_varCheck(current($this->_tokens))) {                                                                                            
     946               0 :                 $this->_query->addFrom(current($this->_tokens));                                                                                               
     947               0 :             } else {                                                                                                                                           
     948               0 :                 require_once 'Erfurt/Sparql/ParserException.php';                                                                                              
     949               0 :                 throw new Erfurt_Sparql_ParserException('Variable, iri or qname expected in FROM', -1,                                                         
     950               0 :                                 key($this->_tokens));                                                                                                          
     951                 :             }                                                                                                                                                  
     952              23 :         } else {                                                                                                                                               
     953               3 :             $this->_fastForward();                                                                                                                             
     954               3 :             if ($this->_iriCheck(current($this->_tokens)) || $this->_qnameCheck(current($this->_tokens))) {                                                    
     955               3 :                 $this->_query->addFromNamed(substr(current($this->_tokens), 1, -1));                                                                           
     956               3 :             } else if ($this->_varCheck(current($this->_tokens))) {                                                                                            
     957               0 :                 $this->_query->addFromNamed(current($this->_tokens));                                                                                          
     958               0 :             } else {                                                                                                                                           
     959               0 :                 require_once 'Erfurt/Sparql/ParserException.php';                                                                                              
     960               0 :                 throw new Erfurt_Sparql_ParserException('Variable, Iri or qname expected in FROM NAMED', -1,                                                   
     961               0 :                                 key($this->_tokens));                                                                                                          
     962                 :             }                                                                                                                                                  
     963                 :         }                                                                                                                                                      
     964              25 :     }                                                                                                                                                          
     965                 :                                                                                                                                                                
     966                 :     /**                                                                                                                                                        
     967                 :      * Parses a GRAPH clause.                                                                                                                                  
     968                 :      *                                                                                                                                                         
     969                 :      * @param  Erfurt_Sparql_GraphPattern $pattern                                                                                                             
     970                 :      * @throws Erfurt_Sparql_ParserException                                                                                                                   
     971                 :      */                                                                                                                                                        
     972                 :     protected function _parseGraph()                                                                                                                           
     973                 :     {                                                                                                                                                          
     974               9 :         $this->_fastForward();                                                                                                                                 
     975               9 :         $name = current($this->_tokens);                                                                                                                       
     976               9 :         if (!$this->_varCheck($name) && !$this->_iriCheck($name) && !$this->_qnameCheck($name)) {                                                              
     977               0 :             $msg = $name;                                                                                                                                      
     978               0 :             $msg = preg_replace('/</', '&lt;', $msg);                                                                                                          
     979               0 :             require_once 'Erfurt/Sparql/ParserException.php';                                                                                                  
     980               0 :             throw new Erfurt_Sparql_ParserException('IRI or Var expected.', -1, key($this->_tokens));                                                          
     981                 :         }                                                                                                                                                      
     982               9 :         $this->_fastForward();                                                                                                                                 
     983                 :                                                                                                                                                                
     984               9 :         if ($this->_iriCheck($name)) {                                                                                                                         
     985               0 :             require_once 'Erfurt/Rdf/Resource.php';                                                                                                            
     986               0 :             $name = Erfurt_Rdf_Resource::initWithIri(substr($name,1,-1));                                                                                      
     987               9 :         } else if($this->_qnameCheck($name)) {                                                                                                                 
     988               3 :             require_once 'Erfurt/Rdf/Resource.php';                                                                                                            
     989               3 :             $name =  Erfurt_Rdf_Resource::initWithIri($this->_query->getFullUri($name));                                                                       
     990               3 :         }                                                                                                                                                      
     991               9 :         $this->_parseGraphPattern(false, false, $name);                                                                                                        
     992               9 :         if (current($this->_tokens) === '.') {                                                                                                                 
     993               1 :             $this->_fastForward();                                                                                                                             
     994               1 :         }                                                                                                                                                      
     995               9 :     }                                                                                                                                                          
     996                 :                                                                                                                                                                
     997                 :     /**                                                                                                                                                        
     998                 :      * Parses a graph pattern.                                                                                                                                 
     999                 :      *                                                                                                                                                         
    1000                 :      * @param  int     $optional Optional graph pattern                                                                                                        
    1001                 :      * @param  int     $union    Union graph pattern                                                                                                           
    1002                 :      * @param  string  $graph    Graphname                                                                                                                     
    1003                 :      * @param  boolean $constr   TRUE if the pattern is a construct pattern                                                                                    
    1004                 :      * @param  boolean $external If the parsed pattern shall be returned                                                                                       
    1005                 :      * @param  int     $subpattern If the new pattern is subpattern of the pattern with the given id                                                           
    1006                 :      */                                                                                                                                                        
    1007                 :     protected function _parseGraphPattern($optional = false, $union = false, $graph = false, $constr = false,                                                  
    1008                 :         $external = false, $subpattern = false)                                                                                                                
    1009                 :     {                                                                                                                                                          
    1010             333 :         $pattern = $this->_query->getNewPattern($constr);                                                                                                      
    1011                 :                                                                                                                                                                
    1012             333 :         if (current($this->_tokens) !== '{') {                                                                                                                 
    1013               0 :             require_once 'Erfurt/Sparql/ParserException.php';                                                                                                  
    1014               0 :             throw new Erfurt_Sparql_ParserException(                                                                                                           
    1015               0 :                 'A graph pattern needs to start with "{".', -1, key($this->_tokens));                                                                          
    1016                 :         }                                                                                                                                                      
    1017                 :                                                                                                                                                                
    1018                 :         // A new graph pattern invalidates the use of all previous blank nodes.                                                                                
    1019             333 :         $this->_dissallowBlankNodes();                                                                                                                         
    1020                 :                                                                                                                                                                
    1021             333 :         if (is_int($optional)) {                                                                                                                               
    1022              43 :             $pattern->setOptional($optional);                                                                                                                  
    1023              43 :         } else {                                                                                                                                               
    1024             333 :             $this->_tmp = $pattern->getId();                                                                                                                   
    1025                 :         }                                                                                                                                                      
    1026                 :                                                                                                                                                                
    1027             333 :         if (is_int($union)) {                                                                                                                                  
    1028              13 :             $pattern->setUnion($union);                                                                                                                        
    1029              13 :         }                                                                                                                                                      
    1030                 :                                                                                                                                                                
    1031             333 :         if (is_int($subpattern)) {                                                                                                                             
    1032              14 :             $pattern->setSubpatternOf($subpattern);                                                                                                            
    1033              14 :         }                                                                                                                                                      
    1034                 :                                                                                                                                                                
    1035             333 :         if ($graph != false) {                                                                                                                                 
    1036               9 :             $pattern->setGraphname($graph);                                                                                                                    
    1037               9 :         }                                                                                                                                                      
    1038                 :                                                                                                                                                                
    1039             333 :         $this->_fastForward();                                                                                                                                 
    1040                 :                                                                                                                                                                
    1041                 :         do {                                                                                                                                                   
    1042             333 :             switch (strtolower(current($this->_tokens))) {                                                                                                     
    1043             333 :                 case 'graph':                                                                                                                                  
    1044               6 :                     $this->_parseGraph();                                                                                                                      
    1045               6 :                     $this->_dissallowBlankNodes();                                                                                                             
    1046               6 :                     break;                                                                                                                                     
    1047             333 :                 case 'union':                                                                                                                                  
    1048              11 :                     $this->_fastForward();                                                                                                                     
    1049              11 :                     $this->_parseGraphPattern(false, $this->_tmp, false, false, false, $subpattern);                                                           
    1050              11 :                     break;                                                                                                                                     
    1051             333 :                 case 'optional':                                                                                                                               
    1052              13 :                     $this->_fastForward();                                                                                                                     
    1053              13 :                     $this->_parseGraphPattern($pattern->patternId, false, false, false, false, null);                                                          
    1054              13 :                     break;                                                                                                                                     
    1055             333 :                 case 'filter':                                                                                                                                 
    1056              10 :                     $this->_parseConstraint($pattern, true);                                                                                                   
    1057                 :                                                                                                                                                                
    1058              10 :                     if (current($this->_tokens) === ')') {                                                                                                     
    1059               8 :                         $this->_fastForward();                                                                                                                 
    1060               8 :                     }                                                                                                                                          
    1061                 :                                                                                                                                                                
    1062              10 :                     $needsDot = false;                                                                                                                         
    1063              10 :                     break;                                                                                                                                     
    1064             333 :                 case '.':                                                                                                                                      
    1065             333 :                 case ';':                                                                                                                                      
    1066                 :                     // Check whether the previous token is {, for this is not allowed.                                                                         
    1067               7 :                     $this->_rewind();                                                                                                                          
    1068               7 :                     if (current($this->_tokens) === '{') {                                                                                                     
    1069               0 :                         require_once 'Erfurt/Sparql/ParserException.php';                                                                                      
    1070               0 :                         throw new Erfurt_Sparql_ParserException('A dot/semicolon must not follow a "{" directly.', -1,                                         
    1071               0 :                                         key($this->_tokens));                                                                                                  
    1072                 :                     }                                                                                                                                          
    1073               7 :                     $this->_fastForward();                                                                                                                     
    1074                 :                                                                                                                                                                
    1075               7 :                     $this->_fastForward();                                                                                                                     
    1076               7 :                     break;                                                                                                                                     
    1077             333 :                 case '{':                                                                                                                                      
    1078              12 :                     $subpattern = $pattern->getId();                                                                                                           
    1079              12 :                     $this->_parseGraphPattern(false, false, false, false, false, $subpattern);                                                                 
    1080              12 :                     break;                                                                                                                                     
    1081             333 :                 case '}':                                                                                                                                      
    1082              39 :                     $pattern->open = false;                                                                                                                    
    1083              39 :                     break;                                                                                                                                     
    1084             314 :                 default:                                                                                                                                       
    1085             314 :                     $this->_parseTriplePattern($pattern);                                                                                                      
    1086             314 :                     break;                                                                                                                                     
    1087             333 :             }                                                                                                                                                  
    1088             333 :         } while ($pattern->open);                                                                                                                              
    1089                 :                                                                                                                                                                
    1090             333 :         if ($external) {                                                                                                                                       
    1091               0 :             return $pattern;                                                                                                                                   
    1092                 :         }                                                                                                                                                      
    1093             333 :         $this->_fastForward();                                                                                                                                 
    1094             333 :     }                                                                                                                                                          
    1095                 :                                                                                                                                                                
    1096                 :     /**                                                                                                                                                        
    1097                 :      * Parses a literal.                                                                                                                                       
    1098                 :      *                                                                                                                                                         
    1099                 :      * @param string $node                                                                                                                                     
    1100                 :      * @param string $sep used separator " or '                                                                                                                
    1101                 :      */                                                                                                                                                        
    1102                 :     protected function _parseLiteral(&$node, $sep)                                                                                                             
    1103                 :     {                                                                                                                                                          
    1104              48 :         if ($sep !== null) {                                                                                                                                   
    1105                 :             do {                                                                                                                                               
    1106              45 :                 next($this->_tokens);                                                                                                                          
    1107              45 :                 $node = $node . current($this->_tokens);                                                                                                       
    1108              45 :             } while ((current($this->_tokens) != $sep));                                                                                                       
    1109              45 :             $this->_checkDtypeLang($node, strlen($sep));                                                                                                       
    1110              45 :         } else {                                                                                                                                               
    1111               3 :             $datatype = '';                                                                                                                                    
    1112               3 :             if (is_string($node) && strpos($node, '.') !== false) {                                                                                            
    1113               2 :                 $datatype = EF_XSD_NS . 'integer';                                                                                                             
    1114               2 :             } else {                                                                                                                                           
    1115               1 :                 $datatype = EF_XSD_NS . 'decimal';                                                                                                             
    1116                 :             }                                                                                                                                                  
    1117                 :                                                                                                                                                                
    1118               3 :             require_once 'Erfurt/Rdf/Literal.php';                                                                                                             
    1119               3 :             $node = Erfurt_Rdf_Literal::initWithLabel($node);                                                                                                  
    1120               3 :             $node->setDatatype($datatype);                                                                                                                     
    1121                 :         }                                                                                                                                                      
    1122              48 :     }                                                                                                                                                          
    1123                 :                                                                                                                                                                
    1124                 :     /**                                                                                                                                                        
    1125                 :      * Parses the solution modifiers of a query.                                                                                                               
    1126                 :      *                                                                                                                                                         
    1127                 :      * @throws Erfurt_Sparql_ParserException                                                                                                                   
    1128                 :      */                                                                                                                                                        
    1129                 :     protected function _parseModifier()                                                                                                                        
    1130                 :     {                                                                                                                                                          
    1131                 :         do {                                                                                                                                                   
    1132             333 :             switch(strtolower(current($this->_tokens))) {                                                                                                      
    1133             333 :                 case 'order':                                                                                                                                  
    1134              25 :                     $this->_fastForward();                                                                                                                     
    1135              25 :                     if (strtolower(current($this->_tokens)) === 'by') {                                                                                        
    1136              25 :                         $this->_fastForward();                                                                                                                 
    1137              25 :                         $this->_parseOrderCondition();                                                                                                         
    1138              25 :                     } else {                                                                                                                                   
    1139               0 :                         require_once 'Erfurt/Sparql/ParserException.php';                                                                                      
    1140               0 :                         throw new Erfurt_Sparql_ParserException('"BY" expected.', -1, key($this->_tokens));                                                    
    1141                 :                     }                                                                                                                                          
    1142              25 :                     break;                                                                                                                                     
    1143             317 :                 case 'limit':                                                                                                                                  
    1144              13 :                     $this->_fastForward();                                                                                                                     
    1145              13 :                     $val = current($this->_tokens);                                                                                                            
    1146              13 :                     $this->_query->setSolutionModifier('limit', $val);                                                                                         
    1147              13 :                     break;                                                                                                                                     
    1148             308 :                 case 'offset':                                                                                                                                 
    1149               6 :                     $this->_fastForward();                                                                                                                     
    1150               6 :                     $val = current($this->_tokens);                                                                                                            
    1151               6 :                     $this->_query->setSolutionModifier('offset', $val);                                                                                        
    1152               6 :                     break;                                                                                                                                     
    1153             302 :                 default:                                                                                                                                       
    1154             302 :                     break;                                                                                                                                     
    1155             333 :             }                                                                                                                                                  
    1156             333 :         } while (next($this->_tokens));                                                                                                                        
    1157             333 :     }                                                                                                                                                          
    1158                 :                                                                                                                                                                
    1159                 :     /**                                                                                                                                                        
    1160                 :      * Parses a String to an RDF node.                                                                                                                         
    1161                 :      *                                                                                                                                                         
    1162                 :      * @param  string $node                                                                                                                                    
    1163                 :      * @return Erfurt_Rdf_Node The parsed RDF node                                                                                                             
    1164                 :      * @throws Erfurt_Sparql_ParserException                                                                                                                   
    1165                 :      */                                                                                                                                                        
    1166                 :     protected function _parseNode($node = false)                                                                                                               
    1167                 :     {                                                                                                                                                          
    1168             314 :         if ($node) {                                                                                                                                           
    1169              22 :             $node = $node;                                                                                                                                     
    1170              22 :         } else {                                                                                                                                               
    1171             313 :             $node = current($this->_tokens);                                                                                                                   
    1172                 :         }                                                                                                                                                      
    1173                 :                                                                                                                                                                
    1174             314 :         if ($node{strlen($node)-1} === '.') {                                                                                                                  
    1175               1 :             $node = substr($node, 0, -1);                                                                                                                      
    1176               1 :         }                                                                                                                                                      
    1177                 :                                                                                                                                                                
    1178             314 :         if ($this->_dtypeCheck($node)) {                                                                                                                       
    1179              28 :             return $node;                                                                                                                                      
    1180                 :         }                                                                                                                                                      
    1181                 :                                                                                                                                                                
    1182                 :                                                                                                                                                                
    1183                 :                                                                                                                                                                
    1184             314 :         if ($this->_bNodeCheck($node)) {                                                                                                                       
    1185              30 :             $node = '?' . $node;                                                                                                                               
    1186                 :                                                                                                                                                                
    1187              30 :             if (isset($this->_usedBlankNodes[$node]) && $this->_usedBlankNodes[$node] === false) {                                                             
    1188               0 :                 require_once 'Erfurt/Sparql/ParserException.php';                                                                                              
    1189               0 :                 throw new Erfurt_Sparql_ParserException('Reuse of blank node id not allowed here.' -1,                                                         
    1190               0 :                             key($this->_tokens));                                                                                                              
    1191                 :             }                                                                                                                                                  
    1192                 :                                                                                                                                                                
    1193              30 :             $this->_query->addUsedVar($node);                                                                                                                  
    1194              30 :             $this->_usedBlankNodes[$node] = true;                                                                                                              
    1195                 :                                                                                                                                                                
    1196              30 :             return $node;                                                                                                                                      
    1197                 :         }                                                                                                                                                      
    1198             312 :         if ($node === '[') {                                                                                                                                   
    1199               2 :             $node = '?' . substr($this->_query->getBlanknodeLabel(), 1);                                                                                       
    1200               2 :             $this->_query->addUsedVar($node);                                                                                                                  
    1201               2 :             $this->_fastForward();                                                                                                                             
    1202               2 :             if (current($this->_tokens) !== ']') {                                                                                                             
    1203               1 :                 prev($this->_tokens);                                                                                                                          
    1204               1 :             }                                                                                                                                                  
    1205               2 :             return $node;                                                                                                                                      
    1206                 :         }                                                                                                                                                      
    1207                 :                                                                                                                                                                
    1208             311 :         if ($this->_iriCheck($node)){                                                                                                                          
    1209              60 :             $base = $this->_query->getBase();                                                                                                                  
    1210              60 :             if ($base != null) {                                                                                                                               
    1211               4 :                 require_once 'Erfurt/Rdf/Resource.php';                                                                                                        
    1212               4 :                 $node = Erfurt_Rdf_Resource::initWithNamespaceAndLocalName(substr($base, 1, -1), substr($node, 1, -1));                                        
    1213               4 :             } else {                                                                                                                                           
    1214              56 :                 require_once 'Erfurt/Rdf/Resource.php';                                                                                                        
    1215              56 :                 $node = Erfurt_Rdf_Resource::initWithIri(substr($node, 1, -1));                                                                                
    1216                 :             }                                                                                                                                                  
    1217              60 :             return $node;                                                                                                                                      
    1218             300 :         } else if ($this->_qnameCheck($node)) {                                                                                                                
    1219             162 :             $node = $this->_query->getFullUri($node);                                                                                                          
    1220             162 :             require_once 'Erfurt/Rdf/Resource.php';                                                                                                            
    1221             162 :             $node = Erfurt_Rdf_Resource::initWithIri($node);                                                                                                   
    1222             162 :             return $node;                                                                                                                                      
    1223             268 :         } else if ($this->_literalCheck($node)) {                                                                                                              
    1224              48 :             if ((substr($node, 0, 1) === '"') || (substr($node, 0, 1) === "'")) {                                                                              
    1225              45 :                 $ch     = substr($node, 0, 1);                                                                                                                 
    1226              45 :                 $chLong = str_repeat($ch, 3);                                                                                                                  
    1227              45 :                 if (substr($node, 0, 3) == $chLong) {                                                                                                          
    1228              12 :                     $ch = $chLong;                                                                                                                             
    1229              12 :                 }                                                                                                                                              
    1230              45 :                 $this->_parseLiteral($node, $ch);                                                                                                              
    1231              45 :             } else {                                                                                                                                           
    1232               3 :                 $this->_parseLiteral($node, null);                                                                                                             
    1233                 :             }                                                                                                                                                  
    1234                 :                                                                                                                                                                
    1235             268 :         } else if ($this->_varCheck($node)) {                                                                                                                  
    1236             243 :             $pos = is_string($node) ? strpos($node, '.') : false;                                                                                              
    1237             243 :             if ($pos) {                                                                                                                                        
    1238               0 :                 return substr($node,0,$pos);                                                                                                                   
    1239                 :             } else {                                                                                                                                           
    1240             243 :                 return $node;                                                                                                                                  
    1241                 :             }                                                                                                                                                  
    1242               0 :         } else if ($node[0] === '<') {                                                                                                                         
    1243                 :             //partial IRI? loop tokens until we find a closing >                                                                                               
    1244               0 :             while (next($this->_tokens)) {                                                                                                                     
    1245               0 :                 $node .= current($this->_tokens);                                                                                                              
    1246               0 :                 if (substr($node, -1) === '>') {                                                                                                               
    1247               0 :                     break;                                                                                                                                     
    1248                 :                 }                                                                                                                                              
    1249               0 :             }                                                                                                                                                  
    1250               0 :             if (substr($node, -1) != '>') {                                                                                                                    
    1251               0 : var_dump($this->_tokens);exit;                                                                                                                                 
    1252                 :                 require_once 'Erfurt/Sparql/ParserException.php';                                                                                              
    1253                 :                 throw new Erfurt_Sparql_ParserException('Unclosed IRI: ' . $node, -1, key($this->_tokens));                                                    
    1254                 :             }                                                                                                                                                  
    1255               0 :             return $this->_parseNode($node);                                                                                                                   
    1256                 :         } else {                                                                                                                                               
    1257               0 :             require_once 'Erfurt/Sparql/ParserException.php';                                                                                                  
    1258               0 :             throw new Erfurt_Sparql_ParserException(                                                                                                           
    1259               0 :                 '"' . $node . '" is neither a valid rdf- node nor a variable.',                                                                                
    1260               0 :                 -1,                                                                                                                                            
    1261               0 :                 key($this->_tokens)                                                                                                                            
    1262               0 :             );                                                                                                                                                 
    1263                 :         }                                                                                                                                                      
    1264                 :                                                                                                                                                                
    1265              48 :         return $node;                                                                                                                                          
    1266                 :     }                                                                                                                                                          
    1267                 :                                                                                                                                                                
    1268                 :     /**                                                                                                                                                        
    1269                 :      * Parses order conditions of a query.                                                                                                                     
    1270                 :      *                                                                                                                                                         
    1271                 :      * @throws Erfurt_Sparql_ParserException                                                                                                                   
    1272                 :      */                                                                                                                                                        
    1273                 :     protected function _parseOrderCondition()                                                                                                                  
    1274                 :     {                                                                                                                                                          
    1275              25 :         $valList = array();                                                                                                                                    
    1276              25 :         $val = array();                                                                                                                                        
    1277                 :                                                                                                                                                                
    1278              25 :         while (strtolower(current($this->_tokens)) !== 'limit' && strtolower(current($this->_tokens)) != false                                                 
    1279              25 :                     && strtolower(current($this->_tokens)) !== 'offset') {                                                                                     
    1280                 :                                                                                                                                                                
    1281              25 :             switch (strtolower(current($this->_tokens))) {                                                                                                     
    1282              25 :                 case 'desc':                                                                                                                                   
    1283               5 :                     $this->_fastForward();                                                                                                                     
    1284               5 :                     $this->_fastForward();                                                                                                                     
    1285                 :                                                                                                                                                                
    1286               5 :                     if ($this->_varCheck(current($this->_tokens))) {                                                                                           
    1287               4 :                         $val['val'] = current($this->_tokens);                                                                                                 
    1288               5 :                     } else if ($this->_iriCheck(current($this->_tokens)) || $this->_qnameCheck(current($this->_tokens)) ||                                     
    1289               1 :                                 in_array(current($this->_tokens), $this->_sops)) {                                                                             
    1290                 :                                                                                                                                                                
    1291               1 :                         $fName = current($this->_tokens);                                                                                                      
    1292                 :                                                                                                                                                                
    1293                 :                         do {                                                                                                                                   
    1294               1 :                             $this->_fastForward();                                                                                                             
    1295               1 :                             $fName .= current($this->_tokens);                                                                                                 
    1296               1 :                         } while (current($this->_tokens) !== ')');                                                                                             
    1297                 :                                                                                                                                                                
    1298               1 :                         $val['val'] = $fName;                                                                                                                  
    1299               1 :                     } else {                                                                                                                                   
    1300               0 :                         require_once 'Erfurt/Sparql/ParserException.php';                                                                                      
    1301               0 :                         throw new Erfurt_Sparql_ParserException('Variable expected in ORDER BY clause.', -1,                                                   
    1302               0 :                                         key($this->_tokens));                                                                                                  
    1303                 :                     }                                                                                                                                          
    1304                 :                                                                                                                                                                
    1305               5 :                     $this->_fastForward();                                                                                                                     
    1306                 :                                                                                                                                                                
    1307               5 :                     if (current($this->_tokens) != ')') {                                                                                                      
    1308               0 :                         require_once 'Erfurt/Sparql/ParserException.php';                                                                                      
    1309               0 :                         throw new Erfurt_Sparql_ParserException('missing ")" in ORDER BY clause.', -1,                                                         
    1310               0 :                                         key($this->_tokens));                                                                                                  
    1311                 :                     }                                                                                                                                          
    1312                 :                                                                                                                                                                
    1313               5 :                     $val['type'] = 'desc';                                                                                                                     
    1314               5 :                     $this->_fastForward();                                                                                                                     
    1315               5 :                     break;                                                                                                                                     
    1316              22 :                 case 'asc':                                                                                                                                    
    1317              10 :                     $this->_fastForward();                                                                                                                     
    1318              10 :                     $this->_fastForward();                                                                                                                     
    1319                 :                                                                                                                                                                
    1320              10 :                     if ($this->_varCheck(current($this->_tokens))) {                                                                                           
    1321              10 :                         $val['val'] = current($this->_tokens);                                                                                                 
    1322              10 :                     } else if ($this->_iriCheck(current($this->_tokens)) || $this->_qnameCheck(current($this->_tokens)) ||                                     
    1323               0 :                                 in_array(current($this->_tokens), $this->_sops)) {                                                                             
    1324                 :                                                                                                                                                                
    1325               0 :                         $fName = current($this->_tokens);                                                                                                      
    1326                 :                                                                                                                                                                
    1327                 :                         do {                                                                                                                                   
    1328               0 :                             $this->_fastForward();                                                                                                             
    1329               0 :                             $fName .= current($this->_tokens);                                                                                                 
    1330               0 :                         } while (current($this->_tokens) !== ')');                                                                                             
    1331                 :                                                                                                                                                                
    1332               0 :                         $val['val'] = $fName;                                                                                                                  
    1333               0 :                     } else {                                                                                                                                   
    1334               0 :                         require_once 'Erfurt/Sparql/ParserException.php';                                                                                      
    1335               0 :                         throw new Erfurt_Sparql_ParserException('Variable expected in ORDER BY clause. ', -1,                                                  
    1336               0 :                                         key($this->_tokens));                                                                                                  
    1337                 :                     }                                                                                                                                          
    1338                 :                                                                                                                                                                
    1339              10 :                     $this->_fastForward();                                                                                                                     
    1340                 :                                                                                                                                                                
    1341              10 :                     if (current($this->_tokens) !== ')') {                                                                                                     
    1342               0 :                         require_once 'Erfurt/Sparql/ParserException.php';                                                                                      
    1343               0 :                         throw new Erfurt_Sparql_ParserException('missing ")" in ORDER BY clause.', -1,                                                         
    1344               0 :                                         key($this->_tokens));                                                                                                  
    1345                 :                     }                                                                                                                                          
    1346                 :                                                                                                                                                                
    1347              10 :                     $val['type'] = 'asc';                                                                                                                      
    1348              10 :                     $this->_fastForward();                                                                                                                     
    1349              10 :                     break;                                                                                                                                     
    1350              13 :                 case ')':                                                                                                                                      
    1351               1 :                     $this->_fastForward();                                                                                                                     
    1352               1 :                     break;                                                                                                                                     
    1353              13 :                 case '(':                                                                                                                                      
    1354               1 :                     $this->_fastForward();                                                                                                                     
    1355              13 :                 default:                                                                                                                                       
    1356              13 :                     if ($this->_varCheck(current($this->_tokens))) {                                                                                           
    1357              11 :                         $val['val'] = current($this->_tokens);                                                                                                 
    1358              11 :                         $val['type'] = 'asc';                                                                                                                  
    1359              13 :                     } else if ($this->_iriCheck(current($this->_tokens)) || $this->_qnameCheck(current($this->_tokens)) ||                                     
    1360               2 :                                     in_array(current($this->_tokens), self::$_sops)) {                                                                         
    1361                 :                                                                                                                                                                
    1362               2 :                         $fName = current($this->_tokens);                                                                                                      
    1363                 :                                                                                                                                                                
    1364                 :                         do {                                                                                                                                   
    1365               2 :                             $this->_fastForward();                                                                                                             
    1366               2 :                             $fName .= current($this->_tokens);                                                                                                 
    1367               2 :                         } while (current($this->_tokens) !== ')');                                                                                             
    1368                 :                                                                                                                                                                
    1369               2 :                         $val['val'] = $fName;                                                                                                                  
    1370               2 :                     } else {                                                                                                                                   
    1371               0 :                         require_once 'Erfurt/Sparql/ParserException.php';                                                                                      
    1372                 :                         //TODO: fix recognition of "ORDER BY ASC(?x)"                                                                                          
    1373                 :                         //throw new Erfurt_Sparql_ParserException('Variable expected in ORDER BY clause.', -1,                                                 
    1374                 :                           //              key($this->_tokens));                                                                                                
    1375                 :                     }                                                                                                                                          
    1376                 :                                                                                                                                                                
    1377              13 :                     $this->_fastForward();                                                                                                                     
    1378              13 :                     break;                                                                                                                                     
    1379              25 :             }                                                                                                                                                  
    1380              25 :             $valList[] = $val;                                                                                                                                 
    1381              25 :         }                                                                                                                                                      
    1382              25 :         prev($this->_tokens);                                                                                                                                  
    1383              25 :         $this->_query->setSolutionModifier('order by', $valList);                                                                                              
    1384              25 :     }                                                                                                                                                          
    1385                 :                                                                                                                                                                
    1386                 :     /**                                                                                                                                                        
    1387                 :      * Adds a new namespace prefix to the query object.                                                                                                        
    1388                 :      *                                                                                                                                                         
    1389                 :      * @throws Erfurt_Sparql_ParserException                                                                                                                   
    1390                 :      */                                                                                                                                                        
    1391                 :     protected function _parsePrefix()                                                                                                                          
    1392                 :     {                                                                                                                                                          
    1393             201 :         $this->_fastForward();                                                                                                                                 
    1394             201 :         $prefix = substr(current($this->_tokens), 0, -1);                                                                                                      
    1395             201 :         $this->_fastForward();                                                                                                                                 
    1396             201 :         if ($this->_iriCheck(current($this->_tokens))) {                                                                                                       
    1397             201 :             $uri = substr(current($this->_tokens), 1, -1);                                                                                                     
    1398             201 :             $this->_query->addPrefix($prefix, $uri);                                                                                                           
    1399             201 :         } else {                                                                                                                                               
    1400               0 :             require_once 'Erfurt/Sparql/ParserException.php';                                                                                                  
    1401               0 :             throw new Erfurt_Sparql_ParserException('IRI expected', -1, key($this->_tokens));                                                                  
    1402                 :         }                                                                                                                                                      
    1403             201 :     }                                                                                                                                                          
    1404                 :                                                                                                                                                                
    1405                 :     /** Starts parsing the tokenized SPARQL Query. */                                                                                                          
    1406                 :     protected function _parseQuery()                                                                                                                           
    1407                 :     {                                                                                                                                                          
    1408                 :         do {                                                                                                                                                   
    1409             334 :             switch (strtolower(current($this->_tokens))) {                                                                                                     
    1410             334 :                 case 'base':                                                                                                                                   
    1411              28 :                     $this->_parseBase();                                                                                                                       
    1412              28 :                     break;                                                                                                                                     
    1413             334 :                 case 'prefix':                                                                                                                                 
    1414             201 :                     $this->_parsePrefix();                                                                                                                     
    1415             201 :                     break;                                                                                                                                     
    1416             334 :                 case 'select':                                                                                                                                 
    1417             316 :                     $this->_parseSelect();                                                                                                                     
    1418             316 :                     break;                                                                                                                                     
    1419             334 :                 case 'describe':                                                                                                                               
    1420               2 :                     $this->_parseDescribe();                                                                                                                   
    1421               2 :                     break;                                                                                                                                     
    1422             333 :                 case 'ask':                                                                                                                                    
    1423               5 :                     $this->_parseAsk('ask');                                                                                                                   
    1424               5 :                     break;                                                                                                                                     
    1425             333 :                 case 'count':                                                                                                                                  
    1426               2 :                     $this->_parseAsk('count');                                                                                                                 
    1427               2 :                     break;                                                                                                                                     
    1428             333 :                 case 'count-distinct':                                                                                                                         
    1429               0 :                     $this->_parseAsk('count-distinct');                                                                                                        
    1430               0 :                     break;                                                                                                                                     
    1431             333 :                 case 'from':                                                                                                                                   
    1432              25 :                     $this->_parseFrom();                                                                                                                       
    1433              25 :                     break;                                                                                                                                     
    1434             333 :                 case 'construct':                                                                                                                              
    1435               9 :                     $this->_parseConstruct();                                                                                                                  
    1436               9 :                     break;                                                                                                                                     
    1437             324 :                 case 'where':                                                                                                                                  
    1438             275 :                     $this->_parseWhere();                                                                                                                      
    1439             275 :                     $this->_parseModifier();                                                                                                                   
    1440             275 :                     break;                                                                                                                                     
    1441              49 :                 case '{':                                                                                                                                      
    1442              49 :                     prev($this->_tokens);                                                                                                                      
    1443              49 :                     $this->_parseWhere();                                                                                                                      
    1444              49 :                     $this->_parseModifier();                                                                                                                   
    1445              49 :                     break;                                                                                                                                     
    1446             334 :             }                                                                                                                                                  
    1447             334 :         } while (next($this->_tokens));                                                                                                                        
    1448             334 :     }                                                                                                                                                          
    1449                 :                                                                                                                                                                
    1450                 :     /**                                                                                                                                                        
    1451                 :      * Parses the SELECT part of a query.                                                                                                                      
    1452                 :      *                                                                                                                                                         
    1453                 :      * @throws Erfurt_Sparql_ParserException                                                                                                                   
    1454                 :      */                                                                                                                                                        
    1455                 :     protected function _parseSelect()                                                                                                                          
    1456                 :     {                                                                                                                                                          
    1457             316 :         $this->_fastForward();                                                                                                                                 
    1458             316 :         $curLow = strtolower(current($this->_tokens));                                                                                                         
    1459             316 :         prev($this->_tokens);                                                                                                                                  
    1460             316 :         if ($curLow === 'distinct') {                                                                                                                          
    1461              11 :             $this->_query->setResultForm('select distinct');                                                                                                   
    1462              11 :         } else {                                                                                                                                               
    1463             305 :             $this->_query->setResultForm('select');                                                                                                            
    1464                 :         }                                                                                                                                                      
    1465                 :                                                                                                                                                                
    1466             316 :         $currentVar = null;                                                                                                                                    
    1467             316 :         $currentFunc = null;                                                                                                                                   
    1468             316 :         $bWaitForRenaming = false;                                                                                                                             
    1469             316 :         while ($curLow != 'from' && $curLow != 'where' && $curLow != "{") {                                                                                    
    1470             316 :             $this->_fastForward();                                                                                                                             
    1471             316 :             $curTok = current($this->_tokens);                                                                                                                 
    1472             316 :             $curLow = strtolower($curTok);                                                                                                                     
    1473                 :                                                                                                                                                                
    1474             316 :             if ($this->_varCheck($curTok) || $curLow == '*') {                                                                                                 
    1475             316 :                 if ($bWaitForRenaming) {                                                                                                                       
    1476               0 :                     $bWaitForRenaming = false;                                                                                                                 
    1477               0 :                     $currentVar->setAlias($curTok);                                                                                                            
    1478               0 :                     if ($currentFunc != null) {                                                                                                                
    1479               0 :                         $currentVar->setFunc($currentFunc);                                                                                                    
    1480               0 :                     }                                                                                                                                          
    1481               0 :                     $this->_query->addResultVar($currentVar);                                                                                                  
    1482               0 :                     $currentVar = null;                                                                                                                        
    1483               0 :                 } else {                                                                                                                                       
    1484             316 :                     if ($currentVar != null) {                                                                                                                 
    1485              70 :                         $this->_query->addResultVar($currentVar);                                                                                              
    1486              70 :                         $currentVar = null;                                                                                                                    
    1487              70 :                     }                                                                                                                                          
    1488             316 :                     require_once 'Erfurt/Sparql/QueryResultVariable.php';                                                                                      
    1489             316 :                     $currentVar = new Erfurt_Sparql_QueryResultVariable($curTok);                                                                              
    1490             316 :                     if ($currentFunc != null) {                                                                                                                
    1491               0 :                         $currentVar->setFunc($currentFunc);                                                                                                    
    1492               0 :                     }                                                                                                                                          
    1493                 :                 }                                                                                                                                              
    1494             316 :                 $currentFunc = null;                                                                                                                           
    1495             316 :             } else if ($curLow == 'as') {                                                                                                                      
    1496               0 :                 if ($currentVar === null) {                                                                                                                    
    1497               0 :                     require_once 'Erfurt/Sparql/ParserException.php';                                                                                          
    1498               0 :                     throw new Erfurt_Sparql_ParserException('AS requires a variable left and right', -1,                                                       
    1499               0 :                                     key($this->_tokens));                                                                                                      
    1500                 :                 }                                                                                                                                              
    1501               0 :                 $bWaitForRenaming = true;                                                                                                                      
    1502             316 :             } else if (in_array($curLow, self::$_sops)) {                                                                                                      
    1503               0 :                 $currentFunc = $curLow;                                                                                                                        
    1504               0 :             }                                                                                                                                                  
    1505                 :                                                                                                                                                                
    1506             316 :             if (!current($this->_tokens)) {                                                                                                                    
    1507               0 :                 require_once 'Erfurt/Sparql/ParserException.php';                                                                                              
    1508               0 :                 throw new Erfurt_Sparql_ParserException(                                                                                                       
    1509               0 :                     'Unexpected end of query.', -1, key($this->_tokens));                                                                                      
    1510                 :             }                                                                                                                                                  
    1511             316 :         }                                                                                                                                                      
    1512                 :                                                                                                                                                                
    1513             316 :         if ($currentVar != null) {                                                                                                                             
    1514             316 :             $this->_query->addResultVar($currentVar);                                                                                                          
    1515             316 :         }                                                                                                                                                      
    1516             316 :         prev($this->_tokens);                                                                                                                                  
    1517                 :                                                                                                                                                                
    1518             316 :         if (count($this->_query->getResultVars()) == 0) {                                                                                                      
    1519               0 :             require_once 'Erfurt/Sparql/ParserException.php';                                                                                                  
    1520               0 :             throw new Erfurt_Sparql_ParserException('Variable or "*" expected.', -1, key($this->_tokens));                                                     
    1521                 :         }                                                                                                                                                      
    1522             316 :     }                                                                                                                                                          
    1523                 :                                                                                                                                                                
    1524                 :     /**                                                                                                                                                        
    1525                 :      * Parses a triple pattern.                                                                                                                                
    1526                 :      *                                                                                                                                                         
    1527                 :      * @param  Sparql_GraphPattern $pattern                                                                                                                    
    1528                 :      */                                                                                                                                                        
    1529                 :     protected function _parseTriplePattern(&$pattern)                                                                                                          
    1530                 :     {                                                                                                                                                          
    1531             314 :         $trp        = array();                                                                                                                                 
    1532             314 :         $prev       = false;                                                                                                                                   
    1533             314 :         $prevPred   = false;                                                                                                                                   
    1534             314 :         $cont       = true;                                                                                                                                    
    1535             314 :         $needsDot   = false;                                                                                                                                   
    1536             314 :         $dotAllowed = true;                                                                                                                                    
    1537             314 :         $sub        = '';                                                                                                                                      
    1538             314 :         $pre        = '';                                                                                                                                      
    1539             314 :         $tmp        = '';                                                                                                                                      
    1540             314 :         $tmpPred    = '';                                                                                                                                      
    1541             314 :         $obj        = '';                                                                                                                                      
    1542                 :                                                                                                                                                                
    1543                 :         do {                                                                                                                                                   
    1544             314 :             switch (strtolower(current($this->_tokens))) {                                                                                                     
    1545             314 :                 case false:                                                                                                                                    
    1546               0 :                     $cont          = false;                                                                                                                    
    1547               0 :                     $pattern->open = false;                                                                                                                    
    1548               0 :                     break;                                                                                                                                     
    1549             314 :                 case 'filter':                                                                                                                                 
    1550              84 :                     $this->_parseConstraint($pattern, false);                                                                                                  
    1551                 :                                                                                                                                                                
    1552              84 :                     if (strtolower(current($this->_tokens)) !== 'filter' &&                                                                                    
    1553              84 :                             strtolower(current($this->_tokens)) !== 'optional') {                                                                              
    1554                 :                                                                                                                                                                
    1555              82 :                         $this->_fastForward();                                                                                                                 
    1556              82 :                     }                                                                                                                                          
    1557                 :                                                                                                                                                                
    1558              84 :                     $needsDot = false;                                                                                                                         
    1559              84 :                     break;                                                                                                                                     
    1560             314 :                 case 'optional':                                                                                                                               
    1561              33 :                     $needsDot = false;                                                                                                                         
    1562              33 :                     $this->_fastForward();                                                                                                                     
    1563              33 :                     $this->_parseGraphPattern($pattern->getId(), false);                                                                                       
    1564              33 :                     break;                                                                                                                                     
    1565             314 :                 case 'union':                                                                                                                                  
    1566               2 :                     $this->_fastForward();                                                                                                                     
    1567               2 :                     $this->_parseGraphPattern(false, $this->_tmp, false, false, false, $pattern->getId());                                                     
    1568               2 :                     break;                                                                                                                                     
    1569             314 :                 case ';':                                                                                                                                      
    1570                 :                     // Check whether the previous token is a dot too, for this is not allowed.                                                                 
    1571              24 :                     $this->_rewind();                                                                                                                          
    1572              24 :                     if (current($this->_tokens) === '.') {                                                                                                     
    1573               0 :                         require_once 'Erfurt/Sparql/ParserException.php';                                                                                      
    1574               0 :                         throw new Erfurt_Sparql_ParserException('A semicolon must not follow a dot directly.', -1,                                             
    1575               0 :                                         key($this->_tokens));                                                                                                  
    1576                 :                     }                                                                                                                                          
    1577              24 :                     $this->_fastForward();                                                                                                                     
    1578                 :                                                                                                                                                                
    1579              24 :                     $prev = true;                                                                                                                              
    1580              24 :                     $needsDot = false;                                                                                                                         
    1581              24 :                     $this->_fastForward();                                                                                                                     
    1582              24 :                     break;                                                                                                                                     
    1583             314 :                 case '.':                                                                                                                                      
    1584             158 :                     if ($dotAllowed === false) {                                                                                                               
    1585               0 :                         require_once 'Erfurt/Sparql/ParserException.php';                                                                                      
    1586               0 :                         throw new Erfurt_Sparql_ParserException('A dot is not allowed here.', -1, key($this->_tokens));                                        
    1587                 :                     }                                                                                                                                          
    1588                 :                                                                                                                                                                
    1589                 :                     // Check whether the previous token is a dot too, for this is not allowed.                                                                 
    1590             158 :                     $this->_rewind();                                                                                                                          
    1591             158 :                     if (current($this->_tokens) === '.') {                                                                                                     
    1592               0 :                         require_once 'Erfurt/Sparql/ParserException.php';                                                                                      
    1593               0 :                         throw new Erfurt_Sparql_ParserException('A dot may not follow a dot directly.', -1,                                                    
    1594               0 :                                         key($this->_tokens));                                                                                                  
    1595                 :                     }                                                                                                                                          
    1596             158 :                     $this->_fastForward();                                                                                                                     
    1597                 :                                                                                                                                                                
    1598             158 :                     $prev = false;                                                                                                                             
    1599             158 :                     $needsDot = false;                                                                                                                         
    1600             158 :                     $this->_fastForward();                                                                                                                     
    1601             158 :                     break;                                                                                                                                     
    1602             314 :                 case 'graph':                                                                                                                                  
    1603               3 :                     $this->_parseGraph();                                                                                                                      
    1604               3 :                     break;                                                                                                                                     
    1605             314 :                 case ',':                                                                                                                                      
    1606               0 :                     require_once 'Erfurt/Sparql/ParserException.php';                                                                                          
    1607               0 :                     throw new Erfurt_Sparql_ParserException('A comma is not allowed directly after a triple.', -1,                                             
    1608               0 :                                     key($this->_tokens));                                                                                                      
    1609                 :                                                                                                                                                                
    1610                 :                     $prev     = true;                                                                                                                          
    1611                 :                     $prevPred = true;                                                                                                                          
    1612                 :                     $this->_fastForward();                                                                                                                     
    1613                 :                     break;                                                                                                                                     
    1614             314 :                 case '}':                                                                                                                                      
    1615             314 :                     $prev = false;                                                                                                                             
    1616             314 :                     $pattern->open = false;                                                                                                                    
    1617             314 :                     $cont = false;                                                                                                                             
    1618             314 :                     $this->_dissallowBlankNodes();                                                                                                             
    1619             314 :                     break;                                                                                                                                     
    1620             314 :                 case '{':                                                                                                                                      
    1621                 :                     //subpatterns opens                                                                                                                        
    1622               2 :                     $this->_parseGraphPattern(false, false, false, false, false, $pattern->getId());                                                           
    1623               2 :                     $needsDot = false;                                                                                                                         
    1624               2 :                     break;                                                                                                                                     
    1625             314 :                 case "[":                                                                                                                                      
    1626              10 :                     $needsDot = false;                                                                                                                         
    1627              10 :                     $prev = true;                                                                                                                              
    1628              10 :                     $tmp  = $this->_parseNode($this->_query->getBlanknodeLabel());                                                                             
    1629              10 :                     $this->_fastForward();                                                                                                                     
    1630              10 :                     break;                                                                                                                                     
    1631             314 :                 case "]":                                                                                                                                      
    1632              10 :                     $needsDot = false;                                                                                                                         
    1633              10 :                     $dotAllowed = false;                                                                                                                       
    1634              10 :                     $prev = true;                                                                                                                              
    1635              10 :                     $this->_fastForward();                                                                                                                     
    1636              10 :                     break;                                                                                                                                     
    1637             314 :                 case "(":                                                                                                                                      
    1638              11 :                     $prev = true;                                                                                                                              
    1639              11 :                     $tmp = $this->_parseCollection($trp);                                                                                                      
    1640              11 :                     $this->_fastForward();                                                                                                                     
    1641              11 :                     break;                                                                                                                                     
    1642             309 :                 case false:                                                                                                                                    
    1643               0 :                     $cont = false;                                                                                                                             
    1644               0 :                     $pattern->open = false;                                                                                                                    
    1645               0 :                     break;                                                                                                                                     
    1646             309 :                 default:                                                                                                                                       
    1647             309 :                     if ($needsDot === true) {                                                                                                                  
    1648               0 :                         require_once 'Erfurt/Sparql/ParserException.php';                                                                                      
    1649               0 :                         throw new Erfurt_Sparql_ParserException('Two triple pattern need to be seperated by a dot. In Query: '.htmlentities($this->_query), -1,
    1650               0 :                                         key($this->_tokens));                                                                                                  
    1651                 :                     }                                                                                                                                          
    1652                 :                                                                                                                                                                
    1653             309 :                     $dotAllowed = false;                                                                                                                       
    1654                 :                                                                                                                                                                
    1655             309 :                     if ($prev) {                                                                                                                               
    1656              33 :                         $sub = $tmp;                                                                                                                           
    1657              33 :                     } else {                                                                                                                                   
    1658             296 :                         $sub = $this->_parseNode();                                                                                                            
    1659             296 :                         $this->_fastForward();                                                                                                                 
    1660             296 :                         $tmp = $sub;                                                                                                                           
    1661                 :                     }                                                                                                                                          
    1662             309 :                     if ($prevPred) {                                                                                                                           
    1663               0 :                         $pre = $tmpPred;                                                                                                                       
    1664               0 :                     } else {                                                                                                                                   
    1665                 :                         // Predicates may not be blank nodes.                                                                                                  
    1666             309 :                         if ((current($this->_tokens) === '[') || (substr(current($this->_tokens), 0, 2) === '_:')) {                                           
    1667               0 :                             require_once 'Erfurt/Sparql/ParserException.php';                                                                                  
    1668               0 :                             throw new Erfurt_Sparql_ParserException('Predicates may not be blank nodes.', -1,                                                  
    1669               0 :                                             key($this->_tokens));                                                                                              
    1670                 :                         }                                                                                                                                      
    1671                 :                                                                                                                                                                
    1672             309 :                         $pre = $this->_parseNode();                                                                                                            
    1673             309 :                         $this->_fastForward();                                                                                                                 
    1674             309 :                         $tmpPred = $pre;                                                                                                                       
    1675                 :                     }                                                                                                                                          
    1676                 :                                                                                                                                                                
    1677             309 :                     if (current($this->_tokens) === '[') {                                                                                                     
    1678               3 :                         $tmp  = $this->_parseNode($this->_query->getBlanknodeLabel());                                                                         
    1679               3 :                         $prev = true;                                                                                                                          
    1680               3 :                         $obj = $tmp;                                                                                                                           
    1681                 :                                                                                                                                                                
    1682               3 :                         require_once 'Erfurt/Sparql/QueryTriple.php';                                                                                          
    1683               3 :                         $trp[] = new Erfurt_Sparql_QueryTriple($sub, $pre, $obj);                                                                              
    1684               3 :                         $dotAllowed = true;                                                                                                                    
    1685               3 :                         $this->_fastForward();                                                                                                                 
    1686               3 :                         continue;                                                                                                                              
    1687             307 :                     } else if (current($this->_tokens) === '(') {                                                                                              
    1688               2 :                         $obj = $this->_parseCollection($trp);                                                                                                  
    1689               2 :                     } else {                                                                                                                                   
    1690             305 :                         $obj = $this->_parseNode();                                                                                                            
    1691                 :                     }                                                                                                                                          
    1692                 :                                                                                                                                                                
    1693             307 :                     require_once 'Erfurt/Sparql/QueryTriple.php';                                                                                              
    1694             307 :                     $trp[] = new Erfurt_Sparql_QueryTriple($sub, $pre, $obj);                                                                                  
    1695             307 :                     $dotAllowed = true;                                                                                                                        
    1696             307 :                     $needsDot = true;                                                                                                                          
    1697             307 :                     $this->_fastForward();                                                                                                                     
    1698             307 :                     break;                                                                                                                                     
    1699             314 :             }                                                                                                                                                  
    1700             314 :         } while ($cont);                                                                                                                                       
    1701                 :                                                                                                                                                                
    1702             314 :         if (count($trp) > 0) {                                                                                                                                 
    1703             314 :             $pattern->addTriplePatterns($trp);                                                                                                                 
    1704             314 :         }                                                                                                                                                      
    1705             314 :     }                                                                                                                                                          
    1706                 :                                                                                                                                                                
    1707                 :     /**                                                                                                                                                        
    1708                 :      * Parses the WHERE clause.                                                                                                                                
    1709                 :      *                                                                                                                                                         
    1710                 :      * @throws Erfurt_Sparql_ParserException                                                                                                                   
    1711                 :      */                                                                                                                                                        
    1712                 :     protected function _parseWhere()                                                                                                                           
    1713                 :     {                                                                                                                                                          
    1714             333 :         $this->_fastForward();                                                                                                                                 
    1715                 :                                                                                                                                                                
    1716             333 :         if (current($this->_tokens) === '{') {                                                                                                                 
    1717             333 :             $this->_parseGraphPattern();                                                                                                                       
    1718             333 :         } else {                                                                                                                                               
    1719               0 :             require_once 'Erfurt/Sparql/ParserException.php';                                                                                                  
    1720               0 :             throw new Erfurt_Sparql_ParserException('Unable to parse WHERE part. "{" expected in Query. ', -1,                                                 
    1721               0 :                             key($this->_tokens));                                                                                                              
    1722                 :         }                                                                                                                                                      
    1723             333 :     }                                                                                                                                                          
    1724                 :                                                                                                                                                                
    1725                 :     /**                                                                                                                                                        
    1726                 :      *   Set all internal variables to a clear state                                                                                                           
    1727                 :      *   before we start parsing.                                                                                                                              
    1728                 :      */                                                                                                                                                        
    1729                 :     protected function _prepare()                                                                                                                              
    1730                 :     {                                                                                                                                                          
    1731             334 :         require_once 'Erfurt/Sparql/Query.php';                                                                                                                
    1732             334 :         $this->_query = new Erfurt_Sparql_Query();                                                                                                             
    1733                 :                                                                                                                                                                
    1734             334 :         $this->_tokens = array();                                                                                                                              
    1735             334 :         $this->_tmp = null;                                                                                                                                    
    1736             334 :     }                                                                                                                                                          
    1737                 :                                                                                                                                                                
    1738                 :     /**                                                                                                                                                        
    1739                 :      * Checks if $token is a qname.                                                                                                                            
    1740                 :      *                                                                                                                                                         
    1741                 :      * @param  string  $token The token                                                                                                                        
    1742                 :      * @return boolean true if the token is a qname false if not                                                                                               
    1743                 :      * @throws Erfurt_Sparql_ParserException                                                                                                                   
    1744                 :      */                                                                                                                                                        
    1745                 :     protected function _qnameCheck($token)                                                                                                                     
    1746                 :     {                                                                                                                                                          
    1747             304 :         $pattern = "/^([^:^\<]*):([^:]*)$/";                                                                                                                   
    1748                 :                                                                                                                                                                
    1749             304 :         if (preg_match($pattern, $token, $hits) > 0) {                                                                                                         
    1750             167 :             $prefs = $this->_query->getPrefixes();                                                                                                             
    1751             167 :             if (isset($prefs[$hits{1}])) {                                                                                                                     
    1752             167 :                 return true;                                                                                                                                   
    1753                 :             }                                                                                                                                                  
    1754               0 :             if ($hits{1} === '_') {                                                                                                                            
    1755               0 :                 return true;                                                                                                                                   
    1756                 :             }                                                                                                                                                  
    1757                 :                                                                                                                                                                
    1758               0 :             require_once 'Erfurt/Sparql/ParserException.php';                                                                                                  
    1759               0 :             throw new Erfurt_Sparql_ParserException('Unbound Prefix: <i>' . $hits{1} . '</i>', -1, key($this->_tokens));                                       
    1760                 :         } else {                                                                                                                                               
    1761             269 :             return false;                                                                                                                                      
    1762                 :         }                                                                                                                                                      
    1763                 :     }                                                                                                                                                          
    1764                 :                                                                                                                                                                
    1765                 :     /** Rewind until next token which is not blank. */                                                                                                         
    1766                 :     protected function _rewind()                                                                                                                               
    1767                 :     {                                                                                                                                                          
    1768             176 :         prev($this->_tokens);                                                                                                                                  
    1769             176 :     }                                                                                                                                                          
    1770                 :                                                                                                                                                                
    1771                 :     /**                                                                                                                                                        
    1772                 :      * Checks if $token is a variable.                                                                                                                         
    1773                 :      *                                                                                                                                                         
    1774                 :      * @param  string  $token The token                                                                                                                        
    1775                 :      * @return boolean true if the token is a variable false if not                                                                                            
    1776                 :      */                                                                                                                                                        
    1777                 :     protected function _varCheck($token)                                                                                                                       
    1778                 :     {                                                                                                                                                          
    1779             332 :         if (isset($token[0]) && ($token{0} == '$' || $token{0} == '?')) {                                                                                      
    1780             250 :             $this->_query->addUsedVar($token);                                                                                                                 
    1781             250 :             return true;                                                                                                                                       
    1782                 :         }                                                                                                                                                      
    1783                 :                                                                                                                                                                
    1784             319 :         return false;                                                                                                                                          
    1785                 :     }                                                                                                                                                          
    1786                 : }                                                                                                                                                              

Generated by PHP_CodeCoverage 1.1.2 using PHP 5.3.10 and PHPUnit 3.6.11 at Mon Jul 2 17:37:52 CEST 2012.